我正在玩模板和部分专业化,但有一个专业化,我不知道如何写...我会简化代码,使其更容易阅读。
让我们的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。有没有人知道编写这种专业化的正确语法?
答案 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;
}