Zack Frost Zack Frost - 3 months ago 11
C++ Question

Why give a typename template parameter a default value of 0 in C++?

The short version (Read if you have no patience like me):



What does setting a typename template parameter to a default of 0 do in C++?

My enable if struct:

/**
* @brief Can be used to enable a template definition using a boolean value
*/
template<lfBool Condition>
struct lfEnableIf
{ };

template<>
struct lfEnableIf<true>
{
typedef lfInt Type;
};


My boolen constant struct:

template<lfBool Val>
struct lfBoolConstant
{
static const lfBool Value = Val;
};

typedef lfBoolConstant<true> lfTrueType;
typedef lfBoolConstant<false> lfFalseType;


My type trait struct (just one of the specializations):

template <typename NumT> struct lfIsArithmetic : lfFalseType{};

template <> struct lfIsArithmetic<lfChar> : lfTrueType{};


And finally my usage of it all:

template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>
struct Test
{
static void print()
{
std::cout << "OK!" << std::endl;
}

};

int main()
{
Test<lfFloat>::print();
Test<lfBool>::print();

return 0;
}


Sorry for the poor for formatting I am writing this on my cell phone.

The long version (Please read if you have the patience so you understand why there is not much code):



So, I am on vacation and don't have access to my workstation or laptop so I thought I would try out AIDE, which if you are unaware is an IDE for android that can compile C++. At home I am designing a game engine that includes Boost and I figured I would try to create something similar to the
enable_if
structures that are in the Boost.Core library. I got it mostly working but it would not compile unless I set the enable if structure in the template I was enabling to default to 0! This is what you do with the Boost
enable_if
and
disable_if
templates. So what does setting a typename template parameter to a default of 0 do in C++?

Thanks!

AnT AnT
Answer

This line

template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>

declares a named template type parameter T and a nameless template value parameter of type lfEnableIf<lfIsArithmetic<T>::Value>::Type, i.e. the second parameter declarations is basically a more convoluted version of simple

template <int N = 0> struct S {};

The type lfEnableIf<lfIsArithmetic<T>::Value>::Type resolves into type lfInt when the enabling condition is met, meaning that the whole thing in such cases is equivalent to

template<typename T, lfInt = 0>

However, since type of that second template parameter is a nested type of a dependent template lfEnableIf, you are required to use the keyword typename to tell the compiler that member Type actually refers to a type and not to something else (i.e. to disambiguate the situation).

Again, the second parameter of the template is nameless, but you can give it a name, if you wish. It won't change anything

template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type V = 0>

In the above example I called it V. The name of that parameter is not used anywhere in the template, which is why there's no real need to specify it explicitly. It is a dummy parameter, which is also the reason it has a dummy default value (you can replace 0 with 42 - it won't change anything either).

In this case keyword typename creates a misleading similarity between the two parameter declarations of your template. In reality in these parameter declarations the keyword typename serves two very very very different unrelated purposes.

In the fist template parameter declaration - typename T - it declares T as a template type parameter. In this role keyword typename can be replaced with keyword class

template <class T, ...

In the second declaration - typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0 - it serves a secondary purpose - it just tells the compiler that lfEnableIf<lfIsArithmetic<T>::Value>::Type is a type and thus turns the whole thing into a value parameter declaration. In this role keyword typename cannot be replaced with keyword class.

Comments