Функция с типом параметра, который имеет конструктор копирования с выбранной неконстантной ссылкой? - PullRequest
2 голосов
/ 16 января 2011

Некоторое время назад меня смутило следующее поведение некоторого кода, когда я хотел написать черту is_callable<F, Args...>. Разрешение перегрузки не вызовет функции, принимающие аргументы неконстантным ref, верно? Почему он не отвергает следующее, потому что конструктор хочет Test&? Я ожидал, что это займет f(int)!

struct Test {
  Test() { }

  // I want Test not be copyable from rvalues!
  Test(Test&) { }

  // But it's convertible to int
  operator int() { return 0; }
};

void f(int) { }
void f(Test) { }

struct WorksFine { };
struct Slurper { Slurper(WorksFine&) { } };
struct Eater { Eater(WorksFine) { } };

void g(Slurper) { }
void g(Eater) { } // chooses this, as expected

int main() {
  // Error, why?
  f(Test());

  // But this works, why?
  g(WorksFine());
}

Сообщение об ошибке

m.cpp: In function 'int main()':
m.cpp:33:11: error: no matching function for call to 'Test::Test(Test)'
m.cpp:5:3: note: candidates are: Test::Test(Test&)
m.cpp:2:3: note:                 Test::Test()
m.cpp:33:11: error:   initializing argument 1 of 'void f(Test)'

Не могли бы вы объяснить, почему один работает, а другой нет?

Ответы [ 2 ]

3 голосов
/ 16 января 2011

Разрешение перегрузки выбирает функцию, наиболее близкую к указанному аргументу. Вы предоставили тест. Преобразование не требуется - используется преобразование личности. При этом функция разрешения выбирает f (Тест). Невозможно скопировать тест из предоставленного вами значения rvalue, но разрешение перегрузки уже успешно выполнено ... преобразование в int никогда не проверяется.

g(Eater) выбрано потому, что типы не совпадают точно, преобразование идентификаторов НЕ используется, и компилятор должен найти работающую процедуру преобразования. g(Slurper) нет, потому что вы не можете сделать один из предоставленного аргумента.

"Почему этот не выходит из строя: struct A { operator int(); }; void f(A&); void f(int); void g() { f(A()); }"

Поскольку f (A &) не является допустимой перегрузкой для предоставленного аргумента. В этом случае параметр является ссылкой, и тот факт, что временные переменные не связываются с неконстантными, позволяет влиять на разрешение. В этом случае это происходит, и та версия функции становится не-кандидатом, оставляя только одну, и она работает.

0 голосов
/ 16 января 2011

По сути, для разрешения перегрузки предполагается, что объект типа A может быть преобразован в объект типа A независимо от какой-либо квалификации cv в любом из двух.

Из черновика n1905:

13.3.3.1: Перегрузка. Разрешение перегрузки. Лучшая жизнеспособная функция. Последовательности явного преобразования

6 Когда тип параметра не является ссылкой , последовательность неявного преобразования моделирует инициализацию копирования параметра из выражения аргумента.Последовательность неявного преобразования - это та, которая требуется для преобразования выражения аргумента в значение типа параметра.[ Примечание : когда параметр имеет тип класса, это концептуальное преобразование, определенное для целей раздела 13;фактическая инициализация определяется в терминах конструкторов и не является преобразованием.- конечная нота ] Любая разница в cv-квалификации верхнего уровня определяется самой инициализацией и не является преобразованием. [ Пример : параметртип A может быть инициализирован из аргумента типа const A. Последовательность неявного преобразования для этого случая является идентичной последовательностью;он не содержит «преобразования» из константы A в A. - конец примера ] Когда параметр имеет тип класса, а выражение аргумента имеет тот же тип, последовательность неявного преобразования является преобразованием идентичности .[...]

...