ajg
ajg

Reputation: 131

Is it possible to simulate default template arguments in partial specializations?

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?

Upvotes: 7

Views: 1782

Answers (1)

Kerrek SB
Kerrek SB

Reputation: 477512

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
};

Upvotes: 4

Related Questions