【问题标题】:Templated function not called未调用模板化函数
【发布时间】:2016-06-25 21:28:10
【问题描述】:

我在我的字符串类中重载了一个函数,但是它永远不会被调用。为什么?

template <class T>
class StringT {
public:
    void assign(const T* ptr);
    template <size_t N> void assign(const T(&ptr)[N]);
};

int main() {
    StringT<char> str;
    str.assign("Hello World"); //calls "void assign(const T* ptr)" although type is (const char[12])
}

【问题讨论】:

标签: c++ templates overloading


【解决方案1】:

如需更多参考,该标准的一些具体参考是:

13.3.3 最佳可行函数

鉴于这些定义,如果对于所有参数 i,ICSi(F1) 不是比 ICSi(F2) 更差的转换序列,则可行函数 F1 被定义为比另一个可行函数 F2 更好的函数,然后...

  • F1 不是函数模板特化,F2 是函数模板特化...

在这种情况下,非模板化函数(显然)不是函数模板特化,"Hello World"char const* 的转换并不比 const char[N] 差,根据表中定义的排名规则“标准转换序列”部分。根据该表,No conversions requiredArray-to-pointer conversion 在重载解析的上下文中都被认为是完全匹配的。同样,如果将模板化重载更改为非模板重载(即 void assign(const T(&amp;ptr)[12]);),则 str.assign("Hello World"); 的编译将由于不明确的调用而失败。

为确保非模板函数不被视为重载,“显式模板参数规范”部分下有以下注释:

注意:空模板参数列表可用于指示给定用途指的是函数模板的特化,即使非模板函数 (8.3.5) 可见,否则会被使用。

因此,您可以为此使用str.assign&lt;&gt;("Hello World");

【讨论】:

  • 感谢您的澄清。您能否也发布该标准的链接?
  • 据我所知,标准版本并非免费提供,但您可以通过latest publicly available draft 链接下的open-std.org/jtc1/sc22/wg21 获取草稿副本。不过,不确定是否有更好的方法......
  • 我仍在尝试将其与以下事实相协调: StringT str; char hw_array[] = "你好世界"; str.assign(hw_array);调用模板版本
  • @Arunas,这是个好问题。根据g++ 6.1,它认为恒等转换序列比(非常量)char[]char const* 转换序列更好(即排名更高);即,当呈现非模板化的void assign(const T(&amp;ptr)[12]); 签名时,不会因为歧义而导致编译失败。此外,当模板版本也可用时,在传递const char[] 时选择char const* 版本。至于它确定这些排名的确切原因,我还没有解析。
【解决方案2】:

当有选择时,编译器会选择最专业的函数。当有一个非模板函数时,它被视为比任何模板函数都更专业

详情here

如果你想保留非模板功能但强制调用模板试一试

str.template assign("Hello World");

【讨论】:

  • 可能取决于编译器,但如果注释掉 const T* 版本,则会调用另一个版本。我没有看到任何有趣的错误。
  • @Arunas 我编辑了我的答案,所以我们的 cmets 现在无关紧要了。我删除了我的
  • 有没有办法让编译器调用模板函数?
  • @Philinator - 查看我的示例(在对您问题的评论中)。我不相信这个答案是正确的,因为如果您将变量声明为 char 数组,则优先调用您的模板化方法。
  • @Philinator 我编辑了我的答案来解决你的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-10
相关资源
最近更新 更多