Я могу сделать это внутри 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...>;
который ставит телегу за лошадью, нет?