为什么在未赋值的操作数内进行包扩展会导致最后一个元素



我可以在decltype():中执行此操作

auto g() -> decltype(1, "", true, new int);

但不是这个:

template <class... Args>
auto g(Args&&... args) -> decltype(args...);

它失败了,因为decltype()内部出现了一个包扩展,但我认为包扩展会导致一个逗号分隔的参数列表。因此,由于逗号运算符的工作方式(它返回最后一个元素),g(a, b, c)的返回类型将是decltype(c)。当你在函数参数列表、模板参数列表、初始值设定项列表等内部展开时,它会起作用。但为什么不是这样呢?

参数包仅在特定情况下进行扩展。您可以通过搜索"包扩展"在标准中找到它们。例如,

功能参数包是一个包扩展(14.5.3)。

(8.3.5/14).

除非在某个地方明确指定包扩展发生在特定上下文中,否则它不会发生,并且通常被语法禁止(,即,语法不正确)。例如,decltype需要一个表达式作为其操作数。1, "", true, new int确实是一个表达式(,是逗号运算符),但args...不是一个表达式。但是,args...表达式列表,因此它可以在函数调用中使用,例如。

逗号运算符与逗号表达式分隔符不同。

逗号运算符接受两个表达式,计算左侧,丢弃它,计算右侧,然后返回结果。

当您有一个表达式列表(如函数调用或初始值设定项列表)时,将使用表达式分隔符。

decltype(a,b,c)decltype(表达式),而不是decltype(表达式列表)。这意味着decltype中的,是运算符逗号。

通常,...扩展只有在语法允许表达式列表时才有效。"生成"的,是表达式分隔符,而不是逗号运算符。

我不知道有什么方法可以使用...来模拟,运算符的行为,包括执行顺序。如果你不在乎他们的评估顺序,你可以这样做:

template<class T, class... Ts>
struct last_type_helper{using type=T;};
template<class T0, class T1, class... Ts>
struct last_type_helper<T0, T1, Ts...>:last_type_helper<T1, Ts...>{}
template<class... Ts>
using last_type=typename last_type_helper<Ts...>::type;
template<class T0>
T0&& last_expression( T0&& t0 ) { return std::forward<T0>(t0); }
template<class T0, class...Ts>
auto last_expression( T0&& t0, Ts&&...ts )->last_type<T0, Ts...>&& {
  return last_expression( std::forward<Ts>(ts)... );
}

然后

template<class...Args>
auto g(Args&&...args) -> decltype(last_expression(args...));

有效,也是

template<class...Args>
auto g(Args&&...args) -> last_type<Args...>;

本末倒置,不是吗?

相关内容

  • 没有找到相关文章

最新更新