我在C ++中发现了令人讨厌的东西,我不知道是否有一个技巧可以避免这种情况而没有开销。问题如下:
对于模板功能,我们可以:
// Function declaration/definition
template<bool Option = false> void myFunction()
{
std::cout<<"Option = "<<Option<<std::endl;
}
// Then I can use :
myFunction<false>();
myFunction<true>();
myFunction(); // <- NO PROBLEM HERE
现在是模板类:
// Class definition/declaration
template<bool Option = false> class MyClass
{
};
// Then I can use :
myClass<false> x;
myClass<true> y;
myClass z; // <- PROBLEM HERE : only "MyClass<> z;" will compile !
为什么会出现这种行为? 有什么诀窍可以避免吗? 对于将optionnal参数作为模板传递的类,我发现这对最终用户来说不方便:他应该能够将默认实现用作非模板化类...
答案 0 :(得分:8)
为什么会出现这种行为的原因?
这是因为函数可以重载,类型不能。
编写函数调用时,编译器会使用该名称填充它可以找到的所有函数的重载集,然后确定哪些函数与传递的参数匹配。现在,为了使用函数模板干净地工作,它允许从参数中推导出模板参数类型。因为通常允许类型参数推断,所以即使参数默认也适用于您的情况。
但是,类型不会超载。虽然myFunction<true>()
和myFunction<false>()
都与他们参与相同重载集的范围相关,但myClass<true>
和myClass<false>
是分开的且无关类型。由于类型名称没有相应的重载,因此没有动机为隐式命名完全专用的模板类添加特殊情况。这些参数永远不会被推断出来,因此只有在它们全部默认的情况下才会有特殊的语法。
有什么诀窍可以避免吗?
一般来说,如果你想获得模板类的模板参数推导,你可以提供一个模板函数包装器(这对C ++ 11 auto最有效)
template <bool Option=false> class MyClass {};
template <bool Option=false> MyClass<Option> make_my_class() {
return MyClass<Option>();
}
// ...
auto z = make_my_class();
否则,我认为使用typedef
(根据Remy的评论)是最好的选择。
答案 1 :(得分:3)
myClass
是一个类模板,而不是一个类。只有myClass<true>
或myClass<>
才是一个类。
同样,myFunction
是一个函数模板,而不是函数。但是,当您调用模板化函数时,可能会为您推导出模板参数,并且不需要明确指定模板参数(如果可以推导出它们) 。因此函数调用表达式myFunction();
有效,第一个参数推导为false
。这只是由于默认参数而不是与函数参数匹配而发生的推论。