2016-12-10 4 views
3

При работе с переменными шаблонами я столкнулся с двумя разными способами написания вызова std::forward, но мне остается интересно узнать, что представляет собой реальная разница между двумя синтаксисами?Различия в синтаксисе в переадресации пакета параметров вариационного шаблона

template<typename... T> 
void one(T&&... args) 
{ 
    foo(std::forward<T&&...>(args...)); 
} 
template<typename... T> 
void two(T&&... args) 
{ 
    foo(std::forward<T&&>(args)...); 
} 

По моим составителям они оба действителен синтаксис, и в большинстве случаев компилятор не жалуется. Но я нашел некоторые случаи, когда один или другой правильный, но компилятор не говорит, почему подробно.

Правильно ли это, что другой?
Служат ли они в разных целях?

+9

Первый ошибочный и фактически не компилируется, за исключением одноэлементных пакетов. –

+0

Это называется расширением пакета, так как это именно так. Вызов первого примера с помощью 'one (2, 2.3, 2.3f);' сделает тело функции 'foo (std: forward (2, 2.3, 2.3f)', который не будет компилироваться , – DeiDei

ответ

6

Месторасположение ... сообщает компилятору, где следует развернуть пакет, один раз для каждого элемента в вещи перед ним (трудно сформулировать легко, но я проиллюстрирую ниже).

Рассмотрим пакет T = {int, double, char} и args = {1, 2.0, '3'}

Ваш первый пример (one) будет расширяться T внутри <>, а затем args внутри () поэтому становится

foo(std::forward<T&&...>(args...)); // becomes: 
foo(std::forward<int&&, double&&, char&&>(1, 2.0, '3')); 

Это не так, как std::forward работает, поскольку он ожидает только один аргумент. Ваш второй пример (two) говорит расширить весь вызов std::forward один раз для каждого элемента в пачках, так что становится

foo(std::forward<T&&>(args)...); // becomes: 
foo(std::forward<int&&>(1), std::forward<double&&>(2.0),std::forward<char&&>('3')); 

А почему они так компилируется отлично, результат идентичен, если вызывается только один аргумент. Если вы никогда не называли это вообще, это не было бы инстанцировано.