Default template arguments can be used to simulate aliases for complex type expressions in a template declaration. For example:
template <typename X,
typename Y = do_something_with<X>::type,
typename Z = some_other_thing_using<X, Y>::type
struct foo { ... X, Y, Z ... };
However, partial specializations may not have default template arguments ([C++11: 14.5.5/8]
), so this trick doesn't work. You might ask yourself why a typedef in the body wouldn't work, and the answer is that the aliases need to be in scope before the class body, in order to do conditional enabling; e.g.:
template <typename T, typename Enable = void>
struct bar;
// Wishful thinking:
template <typename X,
typename Y = do_something_with<X>::type,
typename Z = some_other_thing_using<X, Y>::type>
struct bar <std::vector<X>,
typename enable_if<
some_condition<X, Y, Z>
>::type>
{ ... };
The way I've worked around it is using an auxiliary type:
template <typename X>
struct bar_enabled {
typedef typename do_something_with<X>::type Y;
typedef typename some_other_thing_using<X, Y>::type Z;
static const bool value = some_condition<X, Y, Z>::value;
};
template <typename X>
struct bar <std::vector<X>,
typename enable_if_c<
bar_enabled<X>::value
>::type>
{ ... };
But for various reasons (among them wanting to avoid a separate type, which complicates what I'm doing), I'm hoping that a better solution exists. Any ideas?
You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.
In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
Maybe you can stick the distinction into a base class:
template <typename X, typename Y, bool>
struct BaseImpl { /* ... */ };
template <typename X, typename Y>
struct BaseImpl<X, Y, true> { /* ... */ };
template <typename X, typename Y = typename weird_stuff<X>::type>
struct Foo : BaseImpl<X, Y, some_condition<X, Y>::value>
{
// common stuff
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With