我有以下代码:
template<class T, int I=44> struct test {T j = I;};
template<int J> struct test<int, J> {int j = J;};
int main()
{
test<55> jj;
std::cout << jj.j << std::endl;
return(1);
}
编译器(clang)仅抱怨行test<55> jj
我不明白为什么?有工作吗?
如果它抱怨该行,为什么它不抱怨第二个模板定义呢?
提前致谢。
消息是:
enable.cpp:17:8: error: template argument for template type parameter must be a type
test<55> jj;
^~
enable.cpp:9:16: note: template parameter is declared here
template<class T, int I=44> struct test
答案 0 :(得分:6)
问题在于您还没有理解选择类模板专业化的方式。
您的专长:
template<int J> struct test<int, J> {int j = J;};
不会创建只需传入单个int模板参数的模板。
test<55> jj; // doesn't work because there's no template<int J> struct test
相反它的作用是创建template<class T, int I> struct test
的特化,当template<class T, int I> struct test
的模板参数与特化时匹配时使用,test<int,J>
。
test<int,55> jj; // uses the specialization template<int J> struct test<int, J>
这是标准的关键引用:
在引用类模板特化的类型名称中(例如,
A<int, int, 1>
)参数列表应与模板参数匹配 主模板的列表。 a的模板参数 从主要模板的参数中推断出专业化。 [强调添加]- 14.5.5.1 [temp.class.spec.match] p4
您似乎尝试将int
设置为T
的默认类型,同时为I
设置独立的默认值。我认为您的意图是能够指定类型和值,仅指定类型并将44作为默认值,或者仅指定值并将int作为默认类型。
不幸的是,我不知道如何指定这样的独立默认值。您可以指定默认值(template<class T=int, int I=44> struct test
),但获取默认值也需要接受默认值。
但是,如果你愿意使用第二个名字,那么你可以这样做:
template <int I>
using test_int = test<int, I>;
这会创建一个模板别名,您只需指定一个值:
test_int<55> jj;
这将最终使用任何特殊化test<int, I>
来解决是否存在显式特化或编译器是否生成隐式特化。
答案 1 :(得分:3)
发生第一个错误是因为编译器尝试使用55实例化第一个模板参数(class T
)。这不起作用,因为55本身不是一个类型,而是一个实例化它的。但是,test<int>
有效,因为此处模板参数是模板签名所要求的类型。
你想要的是“currying”类型,又名。模板别名:
template <typename T>
struct test2 = using test<T, 55>;
在这里,您只需提供一个T
来选择55作为固定的第二个参数。但您仍然需要使用该类型,具体为T
,例如test2<double>
。
评论表明您也可能对以下变体感兴趣:
template <int I>
using test3 = test<int, I>;
在这里,您将第一个类型参数修复为int,这允许您像在代码中一样使用它:
test3<55> t;