Partial specialization with a type nested in a template class

I play with templates and partial specialization, but there is one specialization, I do not know how to write ... I will simplify the code to make it easier to read.

Let condiser

template <typename T> class x { ... }; 

I can usually specialize as follows:

 class x<a_type> { ... }; 

Also works with template types:

 template <typename T> class x<std::vector<T>> { ... } 

Now I would like to specialize for a type nested in a template class:

 template <typename T> class y { struct nested_type { y a_member; }; ... }; // Here comes the specialization template <typename T> class x<y<T>::nested_type> { ... }; 

It fails. I also tried putting 'typename' in front of y :: nested_type, but this did not solve the problem. Compiler Error:

 type/value mismatch at argument 1 in template parameter list for 'template <class T> struct x' 

What I want to do seems logical, but I'm not sure if this is possible. I am using C ++ 0x with g ++ - 4.5. Does anyone know the correct syntax for writing such a specialization?

+6
source share
2 answers

The answer is that you cannot do this specialization. This is not a syntax error, but simply something that cannot be implemented. You should see template specialization a bit like function overloading. The compiler must accept the type argument in the workplace, look at the available specializations, find matches, and choose the best (most specialized) one. The problem with your example is that the β€œfind a match” step cannot be implemented with this specialization. The compiler can expect that "nested_type" will be anything, not necessarily a unique type (as in your example), it can also be a nested typedef, for example. Moreover, the compiler cannot predict that it already sees all the specializations of the template β€œy”, so even if nested_type is a unique type embedded in y (a common template), it can be a nested typedef in the upcoming template specialization declaration for the template β€œy” .

As with function overloading and the matching algorithm used there, the compiler is limited in its ability to infer a type, and what are the restrictions that it can make. If you have a specialization for x<int> and then use x<int> , the match is trivial, no deduction is required, no assumptions are required. If you have a specialization like x<T*> and then use x<int*> , the match is easy, T can be inferred as int . If you have a specialization of type x< y<T>::type > and then use any version of x, how should the compiler output T from y :: type? This would have to replace T in y with all possible types that exist around the world to see if there are any that lead to the corresponding nested type. This is an unreasonable expectation, and therefore the possibility of deriving C ++ template types stops here. Very often, in order to know whether one should expect the compiler to be able to solve something, just put it in your place and see if it is even possible remotely (the answer is usually clear).

+5
source

You cannot really do this partial specialization, but there is a workaround that you can use to achieve the desired effect.

Instead of specializing, force the target type to implement what you need.

Here is a minimal example for this:

 #include <vector> #include <iostream> #include <cassert> // Default template defines an interface against the target type. template <class T> struct Traits { using TraitsType = typename T::foo_type; static void foo() { T::foo(); } }; // This is the sample class. template <class T> struct MyStuff { struct NestedType { int x; // It implements the desired features. using foo_type = int; static void foo() { std::cout << "Using Nested version!\n"; } }; }; // For built in types you can use specialization. template <> struct Traits<int> { using TraitsType = double; static void foo() { std::cout << "Using int version.\n"; } }; //... If you can't touch the nested type, the you are SOL. int main() { static_assert(std::is_same<Traits<int>::TraitsType, double>::value); static_assert(std::is_same<Traits<MyStuff<int>::NestedType>::TraitsType, int>::value); static_assert(std::is_same<Traits<MyStuff<double>::NestedType>::TraitsType, int>::value); Traits<int>::foo(); // Prints "Using int version" Traits<MyStuff<int>::NestedType>::foo(); // Prints "Using Nested version!\n" Traits<MyStuff<double>::NestedType>::foo(); // Prints "Using Nested version!\n" return 0; } 
0
source

Source: https://habr.com/ru/post/888936/


All Articles