Почему расширение пакета внутри неоцененного операнда приводит к последнему элементу?

72
8

Я могу сделать это внутри decltype():


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

Но не это:


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

Это не удается, потому что расширение пакета появляется внутри decltype(), но я думал, что расширение пакета приведет к списку аргументов, разделенных запятыми. Таким образом, возвращаемый тип g(a, b, c) будет decltype(c) из-за того, как работает оператор запятой (он возвращает последний элемент). Он работает, когда вы расширяетесь внутри списка параметров функции, списка параметров шаблона, списка инициализаторов и т.д. Но почему здесь это не так?

спросил(а) 2014-10-31T22:16:00+03:00 5 лет, 4 месяца назад
1
Решение
86

Пакеты параметров расширяются только при определенных обстоятельствах. Вы можете найти их в стандарте, ища "расширение пакета". Например,


Пакет параметров функции - это расширение пакета (14.5.3).


(8.3.5/14).


Если это явно не указано где-то, что расширение пакета происходит в конкретном контексте, оно не происходит и обычно запрещено грамматикой (т.е. синтаксически неверно). Например, decltype требует выражения в качестве своего операнда. 1, "", true, new int действительно является выражением (, является оператором запятой), но args... не является выражением. Однако args... - это список выражений, поэтому его можно использовать, например, в вызове функции.

ответил(а) 2014-10-31T22:27:00+03:00 5 лет, 4 месяца назад
80

Оператор запятой не совпадает с разделителем выражений запятой.


Оператор запятой принимает два выражения, оценивает левую сторону, отбрасывает, оценивает правую сторону и возвращает результат.


Разделитель выражений используется, когда у вас есть список выражений, например, вызов функции или список инициализаторов.


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

который ставит корзину после лошади, нет?

ответил(а) 2014-10-31T22:49:00+03:00 5 лет, 4 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема