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

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

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

Но не это:

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

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

3

Решение

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

Пакет параметров функции представляет собой расширение пакета (14.5.3).

(8.3.5 / 14).

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

5

Другие решения

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

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

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

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

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

4

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector