简体   繁体   中英

Template specialization for the base template type for future derived types

I have a class that works as wrapper for some primitives or custom types. I want to write explicit specialization for custom template type. My code that reproduces the problem:


template < class T >
struct A {
    void func() { std::cout << "base\n"; }
};

template <>
struct A<int> {};

template < class T, class CRTP >
struct BaseCrtp {
    void someFunc() {
        CRTP::someStaticFunc();
    }
};

struct DerrType : BaseCrtp<int, DerrType> {
    static void someStaticFunc() {}
};

template < class T, class CRTP >
struct A< BaseCrtp<T, CRTP> > {
    void func() { std::cout << "sometype\n"; }
};

int main() {
    A<DerrType> a;
    a.func(); // print: "base". should be: "sometype"

    return 0;
}

A<DerrType> use default function, not a specialization. How can I make specialization for these set of classes? I will have a lot of types like DerrType , and I want to make common behavior for all of them. DerrType and others will be used as curiously recurring template pattern

Not sure I fully understood what you want, but maybe something like this:

template<typename T>
concept DerivedFromBaseCrtp = requires(T& t) {
    []<typename U, typename CRTP>(BaseCrtp<U, CRTP>&){}(t);
};

template < DerivedFromBaseCrtp T >
struct A<T> {
    void func() { std::cout << "sometype\n"; }
};

The concept basically checks whether T is equal to or is publicly inherited (directly or indirectly) from some specialization of BaseCrtp . Otherwise the call to the lambda would be ill-formed. Template argument deduction only succeeds in the call if the argument and parameter type match exactly or the argument has a derived type of the parameter. If the class is inherited non-publicly, the reference in the call can't bind to the parameter.

The concept will however fail if the type is inherited from multiple BaseCrtp specializations, in which case template argument deduction on the call will not be able to choose between the multiple choices.


Alternatively you can also use the stricter concept

template<typename T>
concept CrtpDerivedFromBaseCrtp = requires(T& t) {
    []<typename U>(BaseCrtp<U, T>&){}(t);
};

which will also require that the type is actually directly using the CRTP pattern on BaseCrtp , not just that a base class is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM