【问题标题】:List initialization of function template arguments with automatic template type deduction使用自动模板类型推导列出函数模板参数的初始化
【发布时间】:2021-11-24 06:27:03
【问题描述】:

这是说明问题的设置。

template <typename T>
struct opt {
  const char* name;
  T x;

  template <typename X>
  opt(const char* name, X&& x)
  : name(name), x(std::forward<X>(x)) { }
};

template <typename T>
opt(const char*, T&&) -> opt< some_type_transformation<T> >;

template <typename... T>
void function(opt<T>&&... opts) {
  // do something with the passed arguments
}

这样,可以使用以下语法。

function(opt("a",1),opt("b",2.),opt("c",3u));

但以下不起作用。

function({"a",1},{"b",2.},{"c",3u});

理论上,有足够的信息来确定在第二种情况下要做什么,因为function 只接受opt&lt;T&gt; 类型的参数,而T 可以使用定义的推导指南进行推导。

可以做些什么来启用第二种更简洁的语法吗?

【问题讨论】:

  • opt 不是聚合;它有一个构造函数(虽然我不确定为什么)。但即使它是一个聚合,这也行不通。
  • 也许我没有直截了当的术语。我指的是{ } 的使用,但没有将类型明确命名为“聚合初始化”,而不是将opt 命名为“聚合”。 opt 有一个构造函数,因为这是一个示例。实际上,构造函数可能会做一些不平凡的事情。
  • 如果“聚合初始化”仅指聚合的初始化,那我就不好了。不要过多地阅读实现细节。我要做的就是将有序的参数集传递给函数,并从集合的元素之一推导出类型。
  • "我指的是 { } 的使用,但没有明确将类型命名为“聚合初始化”" 这只是 list initialization (specifically copy-list-initialization),它可能会调用聚合初始化,具体取决于类型。
  • “有足够的信息来确定在第二种情况下该怎么做” - 如果您从不包含任何其他带有接受 3“事物的函数(模板)的标题”。那么它就不再是足够的信息了。更不用说有时还需要考虑 ADL。最终,当新声明出现在大多数不相关的范围内时,该标准的动机是反对改变行为。在“明显”的情况下失败是关于一致的行为。

标签: c++ templates c++20 template-argument-deduction list-initialization


【解决方案1】:

模板参数推导依赖于使用表达式的类型来匹配模板参数中定义的模式。

Copy-list-initialization(列表初始化,其中使用的类型的名称在使用花括号初始化列表的情况下不能立即可用)是一个过程,其中一系列值与命名的声明相匹配键入以找出要使用的初始化形式。也就是说,它涉及到某种程度的扣除。

您要有效地执行的操作涉及 double 推导,因为花括号初始化列表本身并没有明确定义的类型。您需要使用模板参数中的模式来匹配一组可能的类型及其构造函数与花括号初始化列表的成员。

在某些模板参数推导的情况下,这样的事情在理论上是可能的,但是准确地说明这些情况是非常困难的,因为模板参数推导的工作方式本身就非常复杂。因此,该标准采取了简单的方法并完全禁止它:您不能对涉及模板参数推导的参数使用复制列表初始化,句号。

所以没有更短的形式。你只需要把它拼出来。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    • 2020-07-09
    • 2015-09-19
    相关资源
    最近更新 更多