2013-09-18 2 views
3

Я экспериментирую с совершенной функцией пересылки C++ 11. Компилятор Gnu g ++ сообщает о проблеме неоднозначности привязки функциональных параметров (ошибка показана после исходного кода ниже). Мой вопрос: Почему это так, как после процесса связывания функции-параметра. Я не вижу двусмысленности. Мое рассуждение таково: звоните в tf (a) в main() привязывается к tf (int &) с a является lvalue. Тогда функция Tf пересылает эталонное-значение INT & функционировать г, следовательно, функция недействительного г (интермедиат & а) должен быть однозначно вызван. Таким образом, я не вижу причины двусмысленности. Ошибка исчезает, когда перегруженная функция g (int a) удаляется из кода. Это странно, так как g (int a) не может быть кандидатом для привязки с int & a.Идеальная пересылка и двусмысленность привязки функциональных параметров

Вот мой код:

void g(int &&a) 
{ 
    a+=30; 
} 

void g(int &a) 
{ 
    a+=10; 
} 

void g(int a) //existence of this function originates the ambiguity issue 
{ 
    a+=20; 
} 

template<typename T> 
void tf(T&& a) 
{ 
    g(forward<T>(a));; 
} 

int main() 
{ 
    int a=5; 
    tf(a); 
    cout<<a<<endl; 
} 

Компиляция г ++ -std = C++ 11 perfectForwarding.cpp сообщает следующие ошибки:

perfectForwarding.cpp: In instantiation of ‘void tf(T&&) [with T = int&]’: 
perfectForwarding.cpp:35:7: required from here 
perfectForwarding.cpp:24:3: error: call of overloaded ‘g(int&)’ is ambiguous 
perfectForwarding.cpp:24:3: note: candidates are: 
perfectForwarding.cpp:6:6: note: void g(int&&) <near match> 
perfectForwarding.cpp:6:6: note: no known conversion for argument 1 from ‘int’ to ‘int&&’ 
perfectForwarding.cpp:11:6: note: void g(int&) 
perfectForwarding.cpp:16:6: note: void g(int) 

ответ

4

Add to top Jonathan Wakely's answer.

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

на некоторое время рассмотреть только этот код:

void g(int) {} 

int main() { 
    int a = 5;  // a is an lvalue 
    g(a);   // ok 
    g(std::move(a)); // std::move(a) casts a to an rvalue and this call is also ok 
} 

Это показывает, что функция, которая принимает параметр по значению может принимать как lvalues ​​и rvalues.

Теперь предположим, что мы добавляем

void g(int &) {} 

то первый звонок, g(a);, становится Неоднозначный, потому что g(int &) может принимать Непро- const lvalues ​​и больше ничего. Второй вызов g(std::move(a)) по-прежнему в порядке и по-прежнему вызывает g(int), потому что g(int &) не может принимать значения rvalues.

Теперь замените g(int &) на g(int &&). Последняя функция может принимать только const rvalues.Следовательно, звонок g(a) в порядке и вызывает g(int). Однако g(std::move(a)) теперь неоднозначен.

На этом этапе становится очевидным, что если мы имеем три перегрузки вместе, то два вызова становятся двусмысленными. Фактически, нет причин иметь три перегрузки. В зависимости от типа T, чаще всего мы имеем либо

  1. g(T) или
  2. g(T&) или
  3. g(const T&) или
  4. g(const T&) и g(T&&).
+0

Это гораздо лучший ответ, чем мой, спасибо, Cassio :) –

+0

Действительно более полный ответ, спасибо! –

7

Это странно g (int a) не может быть кандидатом на связывание с int & a.

Это неправда. Если вы удалите перегрузку g(int&), тогда будет вызван g(int). Когда оба объявлены, это неоднозначно, потому что оба являются жизнеспособными кандидатами и не требуют конверсий.

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