6

我正在使用模板和部分专业化,但有一种专业化我不知道如何编写......我将简化代码以使其更易于阅读。

让我们考虑一下

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

通常,我可以这样专攻:

class x<a_type>
{
    ...
};

也适用于模板类型:

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

现在我想对嵌套在模板类中的类型进行专门化:

template <typename T>
    class y
{
    struct nested_type
    {
        y a_member;
    };

    ...
};

// Here comes the specialization

template <typename T>
    class x<y<T>::nested_type>
{
    ...
};

这失败了。我还尝试将 'typename' 放在 y::nested_type 之前,但它并没有解决问题。编译器错误是:

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

我想做的似乎合乎逻辑,但我不确定是否可能。我将 C++0x 与 g++-4.5 一起使用。有人知道编写这种专业化的正确语法吗?

4

2 回答 2

5

答案是你不能做这个专业。这不是语法错误,而只是无法实现的东西。你必须看到模板特化有点像函数重载。编译器必须在使用点获取类型参数,查看可用的特化,找到匹配项,然后选择最好的(最特化的)。您的示例的问题在于,通过这种专业化无法实现“查找匹配”步骤。编译器可以期望“nested_type”是任何东西,不一定是唯一类型(如您的示例中那样),它也可以是嵌套 typedef,例如。此外,编译器无法预测它已经看到模板“y”的所有特化,因此即使nested_type 是嵌套在y(通用模板)中的唯一类型,

就像函数重载和那里使用的匹配算法一样,编译器在推断类型的能力方面受到限制,而限制它的是它可以做出多少假设。如果您有专门的x<int>和以后使用x<int>,匹配是微不足道的,不需要推论,不需要假设。如果你有一个喜欢的特化x<T*>,以后使用x<int*>,匹配很容易,T 可以推断为int。如果你有这样的专业x< y<T>::type >然后使用任何版本的 x,编译器应该如何从 y::type 推导出 T?它必须用 T in y 替换整个世界中存在的所有可能的类型,以查看是否有一个导致匹配的嵌套类型。这是一个不合理的期望,这就是为什么 C++ 模板的类型推断功能到此为止。很多时候,要知道您是否应该期望编译器能够解决某些问题,只需设身处地为它着想,看看它是否有可能(答案通常很清楚)。

于 2011-05-24T17:35:22.613 回答
0

您确实无法进行这种部分专业化,但是有一种解决方法可以使用它来达到预期的效果。

而不是专门化,强制目标类型实现你所需要的。

这是一个最小的例子:

#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;
}
于 2019-10-05T19:13:01.570 回答