嵌套在模板化类中的类型的部分特化

时间:2011-05-24 17:10:00

标签: c++ templates specialization

我正在玩模板和部分专业化,但有一个专业化,我不知道如何写...我会简化代码,使其更容易阅读。

让我们的condiser

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>
{
    ...
};

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

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

我想做的事似乎合乎逻辑,但我不确定是否可行。我正在使用带有g ++ - 4.5的C ++ 0x。有没有人知道编写这种专业化的正确语法?

2 个答案:

答案 0 :(得分:5)

答案是你无法进行此专业化。它不是语法错误,而只是无法实现的东西。你必须看到模板特化有点像函数重载。编译器必须在use-site处获取type参数,查看可用的特化,查找匹配,并选择最佳的(最专业的)。您的示例的问题在于,使用这样的专业化无法实现“查找匹配”步骤。编译器可以期望“nested_type”是任何东西,不一定是唯一类型(就像在你的例子中那样),例如它也可以是嵌套的typedef。此外,编译器无法预测它已经看到模板“y”的所有特化,所以即使nested_type是嵌套在y(通用模板)中的唯一类型,它也可能是即将发布的模板模板特化声明中的嵌套typedef “Y”。

就像函数重载和那里使用的匹配算法一样,编译器在推断类型方面的能力有限,限制它可以做出多少假设。如果您对x<int>进行了专门化并稍后使用x<int>,则匹配很简单,不需要扣除,也不需要任何假设。如果您有x<T*>之类的专业化版,后来使用x<int*>,则匹配很简单,T可以推断为int。如果你有像x< y<T>::type >这样的特化,然后使用任何版本的x,那么编译器应该如何从y :: type中推导出T?它必须替换整个世界中存在的所有可能类型中的T,以查看是否存在导致匹配嵌套类型的类型。这是一个不合理的期望,这就是为什么C ++模板的类型推导功能在此停止。通常,要知道您是否应该期望编译器能够解决某些问题,只需将自己放在一边,看看它是否可以远程实现(答案通常很清楚)。

答案 1 :(得分: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;
}