константные указатели в разрешении перегрузки - PullRequest
5 голосов
/ 23 января 2010

GCC обрабатывает эти два объявления функций как эквивалентные:

void F(int* a) { }
void F(int* const a) { }

test.cpp: в функции 'void F (int *)':

test.cpp: 235: ошибка: переопределение 'void F (int *)'

test.cpp: 234: ошибка: 'void F (int *)', ранее определенное здесь

Это имеет некоторый смысл, потому что вызывающая сторона всегда будет игнорировать const в этом случае ... это влияет только на использование параметра 'a' внутри функции.

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

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

Ответы [ 4 ]

4 голосов
/ 23 января 2010

Стандарт говорит в 8.3.5 / 3, что для целей определения типа функции все cv-квалификаторы, которые непосредственно определяют тип параметра, удаляются. То есть буквально говорится, что функция объявлена ​​как

void foo(int *const a);

имеет тип функции void (int *).

Педантист может утверждать, что это недостаточно убедительно, чтобы утверждать, что приведенная выше декларация должна соответствовать определению, подобному этому

void foo(int *a)
{
}

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

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

На самом деле, в 13.1 / 3 имеется «Примечание», в котором говорится, что объявления функций с эквивалентными объявлениями параметров (как определено в 8.3.5) объявляют такую ​​же функцию . Но это просто примечание, оно ненормативное, что предполагает, что где-то в стандарте должен быть какой-то нормативный текст по тому же вопросу.

3 голосов
/ 23 января 2010

Я думаю, что это так же запрещено, как это:

void foo(int a) {}
void foo(const int a) {}

const для не-ссылок не участвует в перегрузке.

На самом деле вы могли бы даже объявить

void foo(int a);

и позже определите

void foo(const int a) {}

где constness - это просто деталь реализации, которая не заботит вызывающего.

2 голосов
/ 23 января 2010

Это так же, как:

void foo(int);
void foo(const int);

Быть таким же для звонящего. Это связано с тем, что функция получает копию по значению, несмотря ни на что, так что вызывающей стороне все равно, считается ли она const или нет; это не имеет значения.

не законно для компилятора игнорировать такие вещи, но нет разницы в разрешении перегрузки. const применяется к реализации функции.

Недопустимым будет, если обработчик обработает:

void foo(int i)
{
    i = 5; // good
}

void foo(const int)
{
    i = 5; // lolwut?
}

То же самое, игнорируя const.

1 голос
/ 23 января 2010

Я верю, что все наоборот. Любой указатель, даже не являющийся const, может рассматриваться как const:).

...