Partial specialization with type nested in a templated class

巧了我就是萌 提交于 2019-12-04 06:07:39

The answer is that you cannot do this specialization. It is not a syntax error, but just something that cannot be realized. You have to see template specializations a little bit like function overloading. The compiler has to take the type argument at the use-site, look at the specializations available, find matches, and select the best one (most specialized one). The problem with your example is that the "find match" step cannot be realized with such a specialization. The compiler can expect "nested_type" to be anything, not necessarily a unique type (as it is in your example), it could also be a nested typedef, for instance. Moreover, the compiler cannot predict that it is already seeing all the specializations of template "y", so even if nested_type is a unique type nested in y (general template), it could be a nested typedef in an upcoming template specialization declaration for template "y".

Just like with function overloading and the matching algorithm used there, the compiler is limited in its capabilities to deduce the type, and what limits it is how much assumptions it can make. If you have a specialization for x<int> and later use x<int>, the match is trivial, no deduction needed, no assumptions needed. If you have a specialization like x<T*> and later use x<int*>, the match is easy, T can be deduced to be int. If you have a specialization like x< y<T>::type > and then use any version of x, how is the compiler supposed to deduce T from y::type? It would have to substitute for T in y all the possible types that exist in the entire world to see if there is one that results in a matching nested type. That's an unreasonable expectation, and that is why the type deduction capabilities of C++ templates stop here. Very often, to know if you should expect the compiler to be able to resolve something, just put yourself in its shoes and see if it is even remotely possible (the answer is usually clear).

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

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

Here is a minimal example for that:

#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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!