Home > Mobile >  How to access to the actual type of a template specialization type parameter
How to access to the actual type of a template specialization type parameter

Time:11-01

Suppose the following structures:

// struct 'A'
struct A {
    static std::string toString() { return "A"; }
};
// struct 'B' inherits 'A'
struct B : public A {
    static std::string toString() { return "B"; }
};
// struct 'X'
struct X {
    static std::string toString() { return "X"; }
};

then the following template class:

template <typename T>  // Common 'ToString' template type:
class ToString {
public:
    static void print() {
        std::cout << "Other type: " << T::toString() << "\n";
    }
};

and one specialization for A:

template <>
class ToString<A> {  // Specialization of 'ToString' for type 'A' or subtypes of 'A':
public:
    static void print() {
        std::cout << "Subtype of A: " << A::toString() << "\n";
    }
};

The result of:

int main(void) {
    ToString<X>::print(); // OK: invokes 'template<T> ToString::print()'
    ToString<A>::print(); // OK: invokes 'ToString<A>::print()'
    ToString<B>::print(); // KO: I want it invokes 'ToString<A>::print()'
}

is

Other type: X
Subtype of A: A
Other type: B

I have 2 questions:

1: Since B inherits A, why the output of ToString<B>::print() is not something like:

Subtype of A: ...

2: In ToString<A>::print() function, i wrote ... << A::toString() << .... What can I write instead of the (by the way redundant) A to refer to the actual type of the template type parameter which is A itself or any of its subtypes, so that the output for B would be:

Subtype of A: B

Thanks

CodePudding user response:

Specialization for A requires an exact match, but A and B are different types. Inheritance is irrelevant here. Try to make a specialization more generic:

template<typename T, typename = std::bool_constant<true>>
struct ToString {
    // ...
};

template<typename T>
struct ToString<T, std::bool_constant<std::is_base_of_v<A, T>>> {
    static void print() {
        std::cout << "Subtype of A: " << T::toString() << "\n";
    }
};

Now the output is:

Other type: X
Subtype of A: A
Subtype of A: B

The idea is similar to std::void_t trick, which is explained here.

Demo.

In C 20, you can also do this:

template<typename T>
struct ToString {
    // ...
};

template<std::derived_from<A> T>
struct ToString<T> { 
    static void print() {
        std::cout << "Subtype of A: " << T::toString() << "\n";
    }
};
  • Related