3

我可以在里面这样做decltype()

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

但不是这个:

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

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

4

2 回答 2

5

参数包仅在某些情况下扩展。您可以通过搜索“包扩展”在标准中找到它们。例如,

函数参数包是包扩展 (14.5.3)。

(8.3.5/14)。

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

于 2014-10-31T19:27:59.397 回答
4

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

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

当您有一个表达式列表时使用表达式分隔符,例如函数调用或初始化列表。

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

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

我不知道您可以,使用.... 如果您不关心它们的评估顺序,您可以执行以下操作:

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...>;

把车放在马后面,不是吗?

于 2014-10-31T19:49:01.660 回答