【问题标题】:Class Template Argument Deduction in member variables成员变量中的类模板参数推导
【发布时间】:2019-03-06 15:40:59
【问题描述】:

扩展版here.

我们可以创建具有默认模板参数的类模板对象,而无需键入尖括号:

int main()
{
    std::less a;
}

但我们不能对成员变量这样做:

struct S
{
    std::less a; // I want only type std::less<void> here
};

看起来第一种情况是由于CTAD,但为什么编译器不能在第二种情况下推断出std::less&lt;void&gt;?也许我们不应该在那里应用 CTAD,而是提供不同的机制。

这是否被视为标准中的错误?有解决方案吗?

我的用例:

我有一个提供默认参数的类模板,如下所示:

template <typename T = int>
class Foo {};

模板参数是我自己从未使用过的专家专用功能,但它适用于那些需要完全灵活性的 1% 的专家。现在对于其他 99% 的人,我想隐藏 Foo 实际上是一个类模板但它不起作用,因为用户在声明它为成员变量时必须键入 Foo&lt;&gt;,当前的解决方案是:

template <typename T = int>
class BasicFoo {};

using Foo = BasicFoo<>;

但它使实现代码复杂化,一点也不优雅。

【问题讨论】:

  • 不能在成员变量中使用auto这一事实。
  • 只是语法相同并不意味着它是相同的东西。第一个是变量声明,另一个是字段声明。
  • 对于那些想知道 CTAD 意味着什么的人:Class template argument deduction.
  • @Lyberta: "现在对于其他 99% 的人,我想隐藏 Foo 实际上是一个类模板的事实" 好吧,你不能; C++ 不允许你这样做。即使 CTAD 在这里工作,它也不会在一般情况下工作。您不能拥有将Foo 作为参数的函数。您不能与Foo 的静态成员交谈或从中获取成员指针。 CTAD 不是为了隐藏某物是模板的事实。这是一个方便的功能,允许编译器找出它已经知道的内容。
  • @Lyberta:您的问题是关于成员变量中的 CTAD。我正在回答一个附带问题:即使您可以在成员变量中获得 CTAD,您想要 CTAD 在成员变量中的原因也永远不会成功。因此,这样的“答案”不会回答您提出的问题。而且由于其他人都已经根据成员变量中的 CTAD 问题进行了回答,因此您更改问题是不公平的。

标签: c++ templates c++17


【解决方案1】:

不,这不是错误。这是因为同一个成员变量可能会调用不同的构造函数(通过类的构造函数初始化列表调用),可能会产生不同的推导结果。

为防止发生此类冲突,您必须为非静态成员提供模板参数。 (静态成员不是问题,因为它们只有一个构造函数调用)

【讨论】:

  • 没有就地初始化程序,所以在我看来,即使在调用构造函数之前,类型也是固定的。
  • @Lyberta 你是什么意思?正如我试图解释的那样,同一个成员变量可能有不同的构造函数调用。您希望 CTAD 规则如何工作?
  • 我不明白你现在在问什么。如果没有 CTAD,std::less 是一个模板,因此必须照此使用。 std::less&lt;&gt; a; 会非常好用。
  • @Lyberta: "但它暴露了它的模板性,这并不总是可取的。" 它是一个模板; 将暴露给用户是一个事实。 CTAD 并不是要隐藏某物是模板的事实;这是一个方便的功能,可以让人们不必重新输入相同的信息。
  • @Lyberta 因为它不是一种解决方法。 std::less 将永远是一个模板。 CTAD(本质上)是一种打字辅助工具,它允许人们不会重复相同的信息两次——对于构造函数调用和模板参数。我也不喜欢你的问题如何随着时间的推移而演变,现在它变成了一个完全不同的问题,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多