【问题标题】:Why can't constructors deduce template arguments? [duplicate]为什么构造函数不能推断模板参数? [复制]
【发布时间】:2015-04-16 14:18:51
【问题描述】:
template< class T >
class Foo {
public:
  Foo( T t ) { }
};

int main () {
  int i = 0;
  Foo f( i );
}

在上面的代码中,编译器抱怨在 'f' 之前缺少模板参数。我知道从构造函数的参数推断类的模板参数不是标准的一部分,但我的问题是为什么?难道编译器没有隐式实例化Foo&lt;int&gt; 并调用其构造函数所需的所有信息吗?

经过编辑以明确我使用int 调用构造函数(而不是shortlongvoid* 等)

【问题讨论】:

  • 不能 0 也代表 boolchar 或指针吗?还是只是隐式转换?
  • 关于实际问题(不是为什么),目前的 C++ 只使用工厂函数。
  • @mstbaum:虽然是这样,但我不确定这是否相关,因为其意图显然是遵循与函数相同的模板参数推导,所有这些都明确指定。
  • template&lt;typename T&gt; struct Foo { static void bar(T t); }; 也存在类似问题 - 您也不能致电 Foo::bar(0)。无法从方法中推断出类型。
  • 你的愿望在 C++17 中实现了 en.cppreference.com/w/cpp/language/…

标签: c++


【解决方案1】:

因为没有人具体说明它是如何工作的。目前有一个向标准委员会提交的提案,以使其发挥作用。它还列出了一些困难:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4471.html

更新:这是提案的最新版本:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0091r0.html

【讨论】:

  • 在答案本身中总结链接文章中的一些困难可能是个好主意。虽然不是一个仅链接的答案,但如果链接失效,这将失去很多价值。
  • @IMSoP 虽然您对包含信息的看法是正确的,但 C++ 的提议不会很快实现
【解决方案2】:

TL;DR:模板专业化


它们可以,但仅限于函数本身的模板参数,而不是类型。

声明Foo f(0); 是非法的,因为没有名为Foo 的类型。也许你在想

auto f = Foo(0);

但这也是不允许的,因为编译器不知道要在哪个范围内搜索(有无限的潜在类型,其构造函数名为 Foo,并且通过专门化,可能不止一个具有构造函数 Foo(int) )

通常的方法是使用工厂辅助函数:

auto f = make_foo(0);

工厂函数的返回类型取决于其参数的类型推导。


您可以想象工厂函数可以在命名空间范围内自动生成,然后应用通常的函数重载规则,但这会遇到很大的困难,因为类型和构造函数本身都可以有模板参数。这些可以简单地连接起来,但限制是这将排除具有可变参数列表的类模板,因为无法区分类型参数的结束位置和函数参数的开始位置。

【讨论】:

    【解决方案3】:

    Foo 是一个类模板,而不是一个类。它的类型总是需要以某种方式提供,以便生成具有正确类型的类。你不能这样做 Foo 因为 Foo 不是类型,但 Foo&lt;int&gt; 是。它创建了一个这样的类:

    class Foo {
    public:
      Foo( int t ) { }
    };
    

    如果您只提供Foo,编译器将不知道如何生成该类。 Foo&lt;int&gt; f(0) 有效,因为Foo&lt;int&gt; 生成类,用int 替换T。通过您调用构造函数的类型,编译器已经知道构造函数正在接受int

    【讨论】:

    • 干得好,提醒人们模板不是类型。 (我最初使用“+1”而不是前两个词,但显然这是不允许的)
    【解决方案4】:

    你要实例化的类的名字是 Foo&lt;int&gt;(如您所指)。

    也可以写成Foo&lt;short&gt; f(0),或者Foo&lt;unsigned long&gt; f(0), 或Foo&lt;Foo&lt;double&gt;*&gt; f(0)。但是,在这些情况下,如果您只写 Foo f(0),您就不会期望编译器能够猜出类型。

    可以想象,一个 C++可以 已经指定了规则来制定 以某些方式进行一些这样的猜测(例如,文字 0 暗示类型参数 int 而没有其他),但是语言会更多 比现在复杂,还有其他方法 人们会犯编程错误。 实际上在这样的声明中写下你的意思 似乎没有太多要求。

    编辑:发布后,我在另一个答案中注意到 一项使 C++ 具有这样一个特性的提议,确实正如人们所能想象的那样。

    【讨论】:

    • 如果我将实例化更改为int i = 0; Foo f( 0 );,编译器应该拥有实例化Foo&lt;int&gt; 并调用其构造函数所需的所有信息。但是,根据上面的答案,我可以看到为什么编译器会到达 Foo 并且不知道如何处理它并立即报告错误。
    • 对不起,我的意思是int i = 0; Foo f( i );。我同意实施起来很棘手的观点,我只是想更好地了解原因。
    • @wibs 感谢您的澄清,我将相应地替换我之前的评论。从Foo f(i) 甚至Foo f(0) 推断Foo&lt;int&gt; f(0) 的想法并非不合理(请参阅其他地方提到的对语言的拟议更改),我什至最终可能会被说服这是个好主意.我的回答实际上只是为了说明为什么它还没有(还)被添加到语言规范中也是合理的。
    猜你喜欢
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 2022-01-27
    • 1970-01-01
    • 2019-09-14
    相关资源
    最近更新 更多