7

我在 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 !

为什么是这种行为的原因?有什么技巧可以避免这种情况吗?对于具有作为模板传递的可选参数的类,我发现这对最终用户来说并不方便:他应该能够将默认实现用作无模板类...

4

2 回答 2

8

为什么是这种行为的原因?

这是因为函数可以重载,而类型不能。

当您编写函数调用时,编译器会使用该名称填充它可以找到的所有函数的重载集,然后找出哪些与传递的参数匹配。现在,为了让它与函数模板一起干净地工作,它允许从参数中推断出模板参数类型。因为通常允许类型参数推断,所以即使参数是默认值,它也适用于您的情况。

但是,类型不会重载。WhilemyFunction<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 的评论)是最好的选择。

于 2012-10-06T02:07:59.043 回答
3

myClass是类模板,而不是类。只有myClass<true>, 或myClass<>, 是一个类。

同样,myFunction是一个函数模板,而不是一个函数。但是,当您调用模板化函数时,可能会为您推导出模板参数,如果可以推导出模板参数,则无需显式指定模板参数。因此函数调用表达式myFunction();是有效的,并且第一个参数被推导出为false。只是由于默认参数而不是与函数参数匹配而进行了推论。

于 2012-10-06T02:22:38.837 回答