2012-04-20 1 views
15

Уменьшенный образец кода:шаблоны VARIADIC с 'сопзЬ' параметра перегрузки

#include <iostream> 

template<typename T> 
void func(T &x) 
{ 
    std::cout << "non-const " << x << std::endl; 
} 

template<typename T> 
void func(const T &x) 
{ 
    std::cout << "const " << x << std::endl; 
} 

template<typename ...ARGS> 
void proxy(ARGS ...args) 
{ 
    func(args...); 
} 

int main() 
{ 
    int i = 3; 

    func(i); 
    func(5); 
    func("blah"); 

    proxy(i); 
    proxy(5); 
    proxy("blah"); 
} 

Ожидаемый результат:

non-const 3 
const 5 
const blah 
non-const 3 
const 5 
const blah 

Фактический выход:

non-const 3 
const 5 
const blah 
non-const 3 
non-const 5 
non-const blah 

Так или иначе const классификатор функции параметр теряется при использовании вариационного шаблона. Зачем? Как я могу это предотвратить?

PS: протестирована с GCC 4.5.1 и SUSE 11.4

+0

Это не имеет никакого отношения к вариационным шаблонам. Параметры прокси-сервера вашего шаблона не являются ссылками, поэтому аргумент const аргументов функции игнорируется при выводе аргументов шаблона. – Cosyn

ответ

18

Вы просто наткнуться на forwarding problem. Эта проблема решается с использованием perfect forwarding.

В принципе, вы должны принять ваши параметры, RValue-ссылки, и полагаться на std::forward правильно направить их, сохраняя при этом свою природу:

template<typename ...Args> 
void proxy(Args&& ...args) 
{ 
    func(std::forward<Args>(args)...); 
} 
+0

Вам не нужен 'std :: forward '? – juanchopanza

+0

@juanchopanza No. Это передаст все аргументы типа 'std :: forward', но' std :: forward' имеет только один аргумент типа. –

+0

@ R.MartinhoFernandes Правильно, вперед также берет только один параметр, поэтому я думаю, нам нужно 'func (std: forward (args) ...); или что-то в этом роде? образец в ответе не компилируется на мой снимок gcc4.7. – juanchopanza

6

Как Люк уже упоминалось это проблема переадресации и ответ до как предотвратить это использовать совершенная пересылка. Но я постараюсь ответить на другие вопросы в конце:

Так как-то определитель константы параметра функции теряется при вставке вариационного шаблона. Зачем?

У этого есть все, что связано с типом вывода. Игнорируйте, что вы используете VARIADIC шаблоны и рассмотрим простейший шаблон один аргумент:

template <typename T> 
void one_arg_proxy(T arg) { 
    func(arg); 
} 

На месте вызова у вас есть one_arg_proxy(5), то есть аргумент является intRvalue. Определение типа ноги, чтобы выяснить, что тип T должно быть, и правила диктуют, что T является int, поэтому вызов переводится на one_arg_proxy<int>(5) и конкретизация шаблона, который компилируется является:

template <> 
void one_arg_proxy<int>(int arg) { 
    func(arg); 
} 

Теперь вызов func принимает аргумент lvalue, и поэтому версия func, принимающая неконстантную ссылку, является лучшим совпадением (без конверсий), чем тот, который принимает const&, что дает результат, который вы получаете. Проблема здесь в том, что func не вызывается с аргументом proxy, а с внутренней копией, сделанной из него proxy.

 Смежные вопросы

  • Нет связанных вопросов^_^