【问题标题】:C++ template typedef as template function argumentC++ 模板 typedef 作为模板函数参数
【发布时间】:2023-08-31 15:37:02
【问题描述】:

为什么编译器找不到read1 的匹配项?我看不出read1read2 之间的区别; Foo 类中的嵌套 typedef 模板是否有限制?

template<typename T>
class Handle{};

class Foo{
public:
    typedef Handle<Foo> Handle;
};


template<typename T>
void read1(typename T::Handle){}

template<typename T>
void read2(Handle<T>){}


int main(int argc, char** argv)
{
    Foo::Handle f1;    
    read1(f1);

    Foo::Handle f2;
    read2(f2);
}

G++ 编译器输出,(G++ 4.4.5)

g++ -c -I.  main1.cpp 
main1.cpp: In function ‘int main(int, char**)’:
main1.cpp:37: error: no matching function for call to ‘read1(Handle<Foo>&)’

【问题讨论】:

  • 我删除了多余的Internal 命名空间,保持示例简洁。
  • 使用 G++ 4.4.5,您的编辑会破坏代码,g++ -c main.cpp main.cpp:8: error: declaration of ‘typedef class Handle&lt;Foo&gt; Foo::Handle’ main.cpp:3: error: changes meaning of ‘Handle’ from ‘class Handle&lt;Foo&gt;’ main.cpp: In function ‘int main(int, char**)’: main.cpp:27: error: no matching function for call to ‘read1(Handle&lt;Foo&gt;&amp;)’

标签: c++ templates


【解决方案1】:
Foo::Handle f1;    
read1(f1);

传递给 read1 的类型是 Handle&lt;Foo&gt;,而不是 Foo。

模板不是继承。 Handle&lt;Foo&gt; 是一个独特的类,不是 Foo,所以没有 Handle&lt;Foo&gt;::Handle

【讨论】:

    【解决方案2】:
    template<typename T>
    void read1(typename T::Handle)
    {
    }
    

    首先,如果不提供像read1&lt;Foo&gt;(f1) 这样的显式模板参数,您将永远无法调用此函数。阅读SFINAE

    其次,编译器应该如何找出T是什么?它必须测试您可能编写的所有可能类的所有嵌套类型定义。听起来不可能?是的。

    【讨论】:

    • 它不必测试您可能编写的每个类;它只需要测试在 read1 调用时定义的那些类。可能(甚至容易,与编译器处理模板所需的一些事情相比),但不是按照标准完成的。
    • 为什么可以像 read2 那样找到参数?它只需要测试 Foo 没有其他类型
    • 它不仅要测​​试此时定义的所有类,还要测试所有可能的模板实例化(尽管可能以模板形式出现)。但它如何解决模棱两可的问题?通常程序员必须修复这些,但在这种情况下,一些完全不相关的代码更改(不同的命名空间和所有)可能会导致那里的歧义,因此让程序员修复这些并不是一个真正的选择。 @José:在这个简单的例子中,它可能只需要测试 foo,但大多数情况更复杂,而且大多数时候不起作用的语言功能并不是那么受欢迎