编译器选择了错误的模板函数专用化

Compiler chooses wrong template function specialization

本文关键字:函数 专用 选择 错误 编译器      更新时间:2023-10-16

我拼命想让我的专业化发挥作用,但由于将参数推导为不正确的参数,仍然有不可编译的代码。请注意,错误不是关于定义模板,而是关于在错误的模板实现中应用不相关的操作。演示该问题的代码的简化示例是:

struct Test { void Method() const {} };
template<typename T>
void Cmp(T _val) { _val > 1; }
template<>
void Cmp<const Test &>(const Test &_val) { _val.Method(); }
template<>
void Cmp<const char *>(const char *_val) { _val[2]; }
int main()
{
  Test test1;
  char test2[5];
  Cmp(10);    // ok, expected
  Cmp(test1); // error in Cmp(T)?! but expecting to instantiate Cmp(const Test &)
  Cmp(test2); // error in Cmp(T)?! but expecting to instantiate Cmp(const char *)
  return 0;
}

我真的不想使用像Cmp<const Test &>(test1)这样的显式调用(有效)作为AFAIK——编译器应该能够自动推导参数,而这些专门化背后的整个想法是透明地调度Cmp调用(在实际代码中,我定义运算符)。当然,按值专业化Cmp<Test>(Test)可以按预期工作,但对于大型复杂的非POD类,按值传递它是荒谬的。

无论我尝试应用什么修复程序,编译器都顽固地拒绝使用通用模板来选择通过引用进行的专门化。我似乎错过了一些重要的东西,但我真的不知道为什么我的方法不起作用,以及我应该如何构建代码,从非模板化的C++世界中表达这样一个简单的概念,比如通过引用传递类。当然,事实证明谷歌在这个问题上毫无用处我试过GCC 4.2.1和4.4.6。

Cmp(test1);

这里,T是从该自变量推导出的Test。它不会被推断为const Test&,因此您的专业化不匹配,因此主模板被实例化。您需要使您的专业化按值取Test。通过这个声明,确实使用了专门化:

template<>
void Cmp<Test>(Test _val) { _val.Method(); }

Cmp(test1);

这里,T被推导为char*,而不是const char*,因此专业化不匹配。您需要专门针对char*而不是const char*来匹配此项。或者,您可以在进行调用时将参数转换为const char*

const char* test2ptr = test2;
Cmp(test2ptr); 

话虽如此,既然你可以超负荷工作,为什么还要专门从事呢?

template<typename T>
void Cmp(T _val) { _val > 1; }
void Cmp(const Test &_val) { _val.Method(); }
void Cmp(const char *_val) { _val[2]; }
// Add an overload to support arrays of char:
template <unsigned N>
void Cmp(const char (&_val)[N]) { _val[1]; }

您确实应该避免专门化函数模板。这很难,而且在大多数情况下不值得麻烦。

嗯。。。为什么要专门化?只是超载。

void Cmp(const Test &_val) { _val.Method(); }
void Cmp(const char *_val) { _val[2]; }

100%保证选择这些方法。