const position position в объявлении функции

Возможный дубликат:
   Разница между объявлениями const в C ++

#include 

class Bar{};

void foo(const Bar x){}  //l5
void foo(Bar x){}        //l6
void foo(Bar const x){}  //l7

////pointer functions

void foo(const Bar* x){} //l11
void foo(Bar* x){}       //l12
void foo(Bar* const x){} //l13

Выход компилятора: (короткий короткий код l5 , l6 , l7 ), но только l12 , l13 )

untitled.cpp:6:6: error: redefinition of ‘void foo(Bar)’
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here
untitled.cpp:7:6: error: redefinition of ‘void foo(Bar)’
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here
untitled.cpp:13:6: error: redefinition of ‘void foo(Bar*)’
untitled.cpp:12:6: error: ‘void foo(Bar*)’ previously defined here

Что происходит?

  1. В чем смысл каждой из деклараций
  2. Почему все 3 объявления конфликтуют с функциями объекта, но только 2 с указательными функциями?
  3. Пожалуйста, уточните, что конфликт между l12 и l13 , хотя l12 не содержит ключевое слово const /li>
  4. Действительно жаль, если тривиальный вопрос
7

6 ответы

«Проблема» в том, что const значение параметра не участвует в перегрузке!

Во-первых, Bar const и const Bar уже идентичны, поэтому у них автоматически возникнет проблема. Но в качестве параметра функции const не применяется к перегрузке, поэтому версия функции Bar также выглядит одинаково. const в пареметре сообщает компилятору, что вы не собираетесь его изменять в теле функции.

По той же причине, Bar * и Bar * const обрабатываются одинаково: const применяется к значению параметра (не то, что указано to) и не участвует в перегрузке, поэтому вы определили одну и ту же функцию.

С другой стороны, const Bar * означает нечто совершенно другое: указатель не const для объекта const (типа Bar ). Так как тип отличается, он участвует в перегрузке и позволяет этой функции быть уникальной.

5
добавлено

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

Однако, когда вы говорите о указателях, если вы передаете указатель на константу или указатель на константу, есть разница с вызывающим (один не изменит ваш материал, а другой может). Вот почему l11 и l12 не конфликтуют.

l12 и l13, хотя из-за того, что они оба указывают на Bar * (один из них является указателем const, один нет, поэтому такая же проблема, как и l5-l7, нет никакой разницы с вызывающим).

Эта последняя точка может быть немного сложной - обратите внимание, что в то время как int const * a совпадает с const int * a , эти не то же, что и int * const a , первые два являются указателями на константу int, а другая - указателем константы на int (т. е. значение указателя не может измениться в дальнейшем).

1
добавлено

Не имеет значения, ставите ли вы const до или после имени типа.

15 и 17 имеют одинаковый список аргументов параметров.
Считается, что эти 2 функции имеют один и тот же прототип и являются дубликатами.

Функция №1

void foo(const int x) {
return;
}

Функция # 2 - Дублирующий список аргументов параметров

void foo( int const x) {
return;
}

Позиция const такая же, как у 15 и 17 в примере, который у вас есть.

Либо будет работать согласно Википедии:

http://en.wikipedia.org/wiki/Const-correctness

1
добавлено
Повторите свое первое предложение: это не имеет значения для компилятора в данном конкретном контексте. Однако, как правило, const изменяет предшествующее ему значение и ставит const систематически после того, что он изменяет (т.е. int const , а не const int ) делает код более читаемым.
добавлено автор James Kanze, источник
void foo(const Bar x){}
void foo(Bar const x){}

Вышеуказанные два идентичны, потому что оба говорят, что x имеет тип Bar и это const .

void foo(Bar x){}

Это конфликтует с указанным выше 2, потому что x является const или не является деталью реализации вашей функции и отбрасывается компилятором из подпись функции. Таким образом, все 3 функции имеют одну и ту же подпись, которая является void foo (Bar x) .

void foo(Bar* x){}
void foo(Bar* const x){}

Это похоже на предыдущий случай; вы указываете, что указатель x - это const , то есть вы не будете повторно указывать x на что-то еще в своей функции. В обоих случаях объект Bar , который указывает x , не является const . Таким образом, const ness of x является деталью реализации функции.

void foo(const Bar* x){}

Здесь вы указываете, что x указывает на объект Bar , который является const . Это отличается от предыдущих двух случаев, и поэтому конфликта нет.

0
добавлено

Причина, по которой первые три создают конфликт, заключается в том, что компилятор не может определить, какую функцию использовать в любом случае. Когда вы вызываете foo (BarObject); , компилятор может очень хорошо использовать любой из них, был ли объявлен BarObject как const или нет.

Однако на тех, где указаны параметры в качестве указателей, вы вызываете foo (BarPointer); , если BarPointer был объявлен как const Bar * BarPointer; компилятор выберет ] 11 , потому что он гарантирует, что объект, на который указывает, не будет изменен в функции (не в случае, когда он передается по значению, как в первых трех). Если это не const , он не знает, должен ли он вызывать ] 12 или ] 13 , потому что Bar * const x означает, что « x не может указывать на что-либо еще, кроме того, что было передано как параметр», и это не касается вызывающего.

Небольшая ссылка на декларации:

const Bar x//x is an immutable copy of the original parameter.
Bar const x//same as above and gets compiled, but cdecl says it is a syntax error.

const Bar* x//x points to an object that can't be changed.
Bar* const x//x can't point to any other object than the parameter passed.
0
добавлено

Для первых трех функций - const не имеет значения при перегрузке разрешения в случае переменной, передаваемой значением . Копия аргумента, созданного в стеке, и это не имеет смысла, если эта копия изменилась или не с внешней (вызывающей) точки зрения. Это важно для самой функции (внутри).

Для второго случая, основанные на указателях функции, это важная часть разрешения перегрузки функции, поскольку копии не создаются в стеке и из внешней (вызывающей) точки зрения, это означает, что функция будет или не будет изменять значение аргумента.

Для последних двух функций используйте, скажем, компилятору: указатель x на Bar , а это значение Bar , указанное x code> Я могу изменить. Но в первом случае вы можете изменить значение самого указателя x (скажем, указать на другую Bar ), противоположную второму случаю. И здесь мы находимся в первой ситуации - копии самих указателей находятся в стеке, и нет смысла перегружать разрешение, если они меняются внутри функции или нет.

0
добавлено
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest