2014-12-10 6 views
1

Кодов ниже:Перегрузки функции с другим идентичными подписями, чтобы принять как ссылку и константную ссылку

struct A {}; 

void f (A& a) {std::cout << "No const" << std::endl;} 

void f (const A& a) {std::cout << "const" << std::endl;} 

int main(){ 
    f(A()); // indicated as line A, output will be "const". 
} 

Вопрос 1):

Почему выходной линия A «s„Const“, хотя A() является неконстантным объектом?

Я считаю, что компилятор производит код, эквивалентный:

const A tempA; 
f(tempA); 

Является ли это правильно?

Вопрос 2), если две функции F изменяются, как показано ниже, изменение ссылки на тип значения

void f (A a) {std::cout << "No const" << std::endl;} 

void f (const A a) {std::cout << "const" << std::endl;} 

Приведенные выше коды не могут быть собраны. Компилятор выдает ошибки «переопределения функции f». Я могу понять, почему ошибка была выдана компилятором, потому что можно преобразовать const A в A и наоборот. Таким образом, во время компиляции невозможно решить. Это правильно ?

Мне все еще очень любопытно, что это очень хорошо определено в спецификации C++?

ответ

5

Почему линия А по выходу "Уста", даже если A() является объектом без сопзЬ?

Выражение A() создает prvalue временный характера, которые не могут быть связаны неконстантной ссылкой-значения, таким образом, void f (const A& a) является единственной жизнеспособной перегрузкой.

Мне все еще очень любопытно, что это очень хорошо определено в спецификации C++?

§13.1 [over.load]/р3:

- декларации параметров, которые отличаются только в присутствии или в отсутствие const и/или volatile являются эквивалентны. То есть, спецификаторы типа и для каждого типа параметров игнорируются, когда определяет, какая функция объявляется, определяется или вызывается.[Пример:

typedef const int cInt; 
int f (int); 
int f (const int);   // redeclaration of f(int) 
int f (int) { /* ... */ } // definition of f(int) 
int f (cInt) { /* ... */ } // error: redefinition of f(int) 

- конец пример]

только const и volatile типа спецификаторов на самом внешнем уровне спецификации типа параметра игнорируется таким образом; const и volatile Спецификаторы типов, закодированные в спецификации типа параметра, являются значительными и могут использоваться для различения описаний перегруженных функций. В частности, для любого типа T «указатель на T», «указатель на const T» и «указатель на volatile T» считаются отдельными типами параметров, как «ссылка на T», «ссылка на const T» и «ссылка на volatile T

для параметров типа A и const A та же последовательность преобразования применяется при инициализации любого аргумента, конвертируемых в A, компилятор никогда не будет иметь возможность выбирать между ними.

Для параметров типа A& и const A& могут быть разные выражения, чтобы компилятор мог выбрать лучшую последовательность преобразования или исключить любого кандидата из набора кандидатов.

+0

Большое спасибо за ваш ответ. Я получаю его. –

0

Вы создаете временный объект для передачи здесь функции f (A()); Построенный объект используется только в функции. Временами всегда являются константы. Это будет работать, если вы создадите объекты вне вызова функции. Ex.

A nonConstA; 
f(nonConstA); //Will print "No const" 

const A constA; 
f(constA); //Will print "const" 
+1

«Времена всегда« const ». Не верно. Правила привязки их к ссылкам lvalue требуют, чтобы ссылка lvalue была ссылкой-на -const', но это не означает, что временное само является неизменным (это не так). В частности, ваша теория запретит «A && ref = A();» и сломает всю семантическую модель перемещения. –

2

В своем первом случае:

A() создает временный характер, который передается в вашей функции. Временные пользователи могут привязываться только к const lvalue по спецификации. Таким образом, выбрана ваша перегрузка const.

Обратите внимание, что расширение Visual C++ позволяет ссылаться на временные ссылки, не связанные с константой lvalue. Это нестандартное и включено по умолчанию, поэтому будьте осторожны. Я не знаю, какая перегрузка будет выбрана в этом случае.

В вашем втором случае:

const классификатор параметра функции квалифицирует сам параметр, а не объект, который является его аргумент. Таким образом, единственное различие между двумя вашими функциями - const ness вашего параметра внутри функция.
В таких случаях, как ваш первый, где параметр является указателем или ссылкой на объект const const, правила преобразования и привязки делают одну перегрузку жизнеспособной (или предпочтительной) для последующих вызовов функций.
В этом втором случае, однако, ничто не квалифицирует ваш аргумент, поэтому обе перегрузки неразличимы по дизайну (не более поздний вызов может быть однозначным), следовательно, ошибка «множественных определений».

+0

Большое спасибо за ваш ответ. –

+2

Temporaries могут привязываться к ссылкам, отличным от 'const', просто отлично. : P –

+0

@LightnessRacesinOrbit стандартно-совместимое доказательство или этого не произошло: p – Quentin

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