Search code examples
c++c++11templatestemplate-meta-programming

Can I get name / reference to specialization value inside template specialization?


My code:

enum class list{one, two};
template <list T> class Base;
template <> class Base <list::one>{
    A a{list::one};
    B b{list::one};
    C c{list::one};
};
template <> class Base <list::two>{
    B b{list::two};
    C c{list::two};
    D d{list::two};
};

But I would like to avoid duplicating code, and use reference to specialization value, like this:

template <> class Base <list::one>{
    A a{T};
    B b{T};
    C c{T};
};
template <> class Base <list::two>{
    B b{T};
    C c{T};
    D d{T};
};

I can make sludge temporary variable, but does not look good too:

template <> class Base <list::one>{
    list T = list::one;
    A a{T};
    B b{T};
    C c{T};
};

Is there are any way to get reference to template specialization value?


Solution

  • In the following example I'm using SFINAE to make T available in the definition of Base. Specifically I have done the following:

    • added one dummy type parameter to the primary template,
    • made the two specialization partial by not specifying the parameter T (and specifying the second dummy type parameter),
    • specified the second dummy type parameter enforcing that T is equal to list::one and list::two in the two specializations, via std::enable_if_t.
    #include <iostream>
    #include <type_traits>
    
    enum class list{one, two};
    
    // to make the code compile
    class A { public: A(list) {} };
    class B { public: B(list) {} };
    class C { public: C(list) {} };
    class D { public: D(list) {} };
    
    // primary template (second param's sole purpose is to allow partial spec.)
    template <list T, typename = void>
    class Base;
    
    // partial specialization #1
    template <list T>
    class Base <T, std::enable_if_t<T == list::one>>{
        A a{T};
        B b{T};
        C c{T};
      public:
        Base() { std::cout << "list::one\n"; }
    };
    
    // partial specialization #2
    template <list T>
    class Base <T, std::enable_if_t<T == list::two>>{
        B b{T};
        C c{T};
        D d{T};
      public:
        Base() { std::cout << "list::two\n"; }
    };
    
    int main() {
        Base<list::one> o;
        Base<list::two> t;
    }
    

    This is a pretty standard way of using taking advantage of SFINAE via std::enable_if. Similar examples can be found on cppreference page on std::enable_if, where the last example (the one with the first comment // primary template) resambles the code above.