23

So what I want to do is to create a template class which may or may not contain a member variable based on the template argument passed in. like following:

template<typename T, bool flag>
class base
{
   foov<std::enable_if<flag, T>::type> m_var;
};

the above code could not survive the compiler.

Does anyone know how I can achieve this?

Nowibananatzki
  • 756
  • 1
  • 9
  • 19
  • Since (member sub)objects always take up space (at least one byte, with the exception of bitfields), this cannot be done inside the class itself. You can use (multiple) inheritance to get a similar effect, many compilers implement what's called the *empty base class optimization*, i.e. empty base class subobjects don't take up space. Alternatively, (partial) specialization is also possible. – dyp Aug 25 '14 at 23:50
  • @dyp, I can't really follow you. could you elaborate on empty base class optimization? How can I use that to achieve compile time member variable declaration? – Nowibananatzki Aug 26 '14 at 02:48
  • CoffeeandCode has shown how to do that. The second `base_class` specialization won't take up any space in `derived_class` objects on compilers that support the empty base class optimization. – dyp Aug 26 '14 at 12:00

4 Answers4

26

Have a base class with enabled/disabled members based on template parameters:

template<typename T, typename Enable = void>
class base_class;

// my favourite type :D
template<typename T>
class base_class<T, std::enable_if_t<std::is_same<T, myFavouriteType>::value>>{
    public:
        int some_variable;
};

// not my favourite type :(
template<typename T>
class base_class<T, std::enable_if_t<!std::is_same<T, myFavouriteType>::value>>{
    public:
        // no variable
};

template<typename T>
class derived_class: public base_class<T>{
    public:
        // do stuff
};

This should give you a nice way to enable/disable members based on type.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
RamblingMad
  • 5,332
  • 2
  • 24
  • 48
  • thanks for the reply, but I need to enable/disable member variable. Is there anyway I can do that? – Nowibananatzki Aug 26 '14 at 04:20
  • Same thing, just with variables instead of functions :L – RamblingMad Aug 26 '14 at 04:21
  • @Norwizki No, SFINAE requires specialization and only templates may be specialized. There's a major upcoming language feature "concepts" which might do what you ask, but it's still a few years away. – Potatoswatter Aug 26 '14 at 04:50
  • How can I access the member variable in the derived class? When I try to access it (wrapping the call in `if constexpr(std::is_same_v)`) it still complains that the variable is not defined. Example: https://godbolt.org/z/78Tx6eqfq – kekpirat Dec 07 '22 at 07:07
  • @kekpirat sorry for the late reply. It's pretty ugly, but you have to explicitly cast `this` to its base: https://godbolt.org/z/zaG4Yh333 – RamblingMad Dec 27 '22 at 06:46
0

I think this is what you are looking for.

The class template does not have any member data by default.

template<typename T, bool flag>
class base
{
};

Add a specialization of the class template that has the member data.

template<typename T>
class base<T, true>
{
   foov<T> m_var;
};
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0
#pragma once
#include <type_traits>

template <typename T, bool D, typename Enabled=void>
class Node;


template <typename T, bool D>
class Node<T, D, std::enable_if_t<D>>
{
public:
    Node(const T& v) : value(v) {}

private:
    T value;
    Node* next = nullptr;
};

template <typename T, bool D>
class Node<T, D, std::enable_if_t<!D>>
{
public:
    Node(const T& v) : value(v) {}

private:
    T value;
    Node* next = nullptr;
    Node* prev = nullptr;
};

Single or double linked list node based on boolean flag

Alexander Katz
  • 119
  • 1
  • 4
  • Provide some comments. – M-- Apr 26 '17 at 02:16
  • Provide some comments PLEASE. – Alexander Katz May 21 '17 at 09:25
  • Whatever I and other SO members are commenting is not an order, is a suggestion. And "please" is embedded in them. Just tryimg to make your answer/question, etc. better. Sorry for misunderstanding anyway. – M-- May 22 '17 at 00:33
  • 3
    Your `std::enable_if` is superfluous. You could achieve the same thing by just specializing based on `D`, which another answer already does with much more brevity. – RamblingMad Jul 23 '17 at 07:13
-2

I have a workaround for this. Probably looks ugly but does resolve some of my issues

First I define a type with zero size:

typedef int zero[0];

Next I create a macro:

#ifndef VAR

#define VAR(Enable,YourType,VarName) \    

std::conditional< Enable,YourType,zero >::type VarName

#endif

Then a class like this:

template < int Cond >
class Foo
{
    VAR(Cond == 0,int,var);

    void print()
    {
        if (!sizeof(var)) return;
        //...
    }
};

When you are using a result like var, check the size of it before using it. If the size is zero, it is invalid.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
DAG
  • 417
  • 4
  • 7
  • 1
    This is invalid in any case. An array must not have size 0: http://stackoverflow.com/a/9723093/2757035 Instantiating such an array makes the program ill-formed and invokes undefined behaviour, if your compiler even allows it, which it shouldn't unless it has a really lax attitude to default warnings and you haven't turned any on. Telling users to compile such a program and just check its results is irresponsible when those results really mean nothing due to how invalid the code is. The array is invalid, so all bets are off: an errant compiler might as well go all-out and give it non-0 storage. – underscore_d May 06 '17 at 18:20