Неоднозначный вызов перегруженной статической функции
Я смущен этой ситуацией, и googling не дал мне ответа. В основном у меня есть следующий простой код, который не компилируется:
#include <iostream>
class A
{
public:
int a(int c = 0) { return 1; }
static int a() { return 2; }
};
int main()
{
std::cout << A::a() << std::endl;
return 0;
}
При компиляции этого GCC 4.2 говорит, что вызов A::a()
в main()
неоднозначен с обеими версиями a()
допустимых кандидатов. Компилятор Apple LLVM 3.0 компилируется без ошибок.
Почему gcc запутался в какой функции я хочу позвонить? Я думал, что очевидно, что, отбирая a()
с A::
, я прошу версию функции static
. Естественно, этот код до сих пор не компилируется, если я удаляю функцию static
a()
, потому что A::a()
не является допустимым синтаксисом для вызова не static
a()
.
Спасибо за любой комментарий!
Ответы
Ответ 1
Причина этого в том, что С++ указывает, что это неоднозначно. Разрешение перегрузки указывает, что для A::a
, так как this
не входит в область видимости, список аргументов в этом вызове дополняется надуманным аргументом объекта A вместо *this
. Разрешение перегрузки не исключает нестатические функции-члены, но вместо этого
Если список аргументов дополняется надуманным объектом, а разрешение перегрузки выбирает одну из нестатических функций-членов T, вызов плохо сформирован.
Это недавно было предметом обширного обсуждения как в комитете в контексте основной проблемы 1005. См. основная проблема 364, в которой рассматривается изменение этого правила, но этого не произошло.
Ответ 2
Причиной является разрешение имен, прежде чем что-либо еще делает компилятор, например, выяснение, какую перегруженную функцию использовать.
Квалификация функции с помощью A::
просто говорит компилятору "заглянуть внутрь A
, чтобы найти имя A
". Это фактически не помогает решить, к какой функции вы обращаетесь.
ИЗМЕНИТЬ
Итак, когда вы печатаете A::a()
, сначала компилятор думает "смотрите A
для функции-члена или члена, который может использовать operator()
".
Затем компилятор думает: "Хорошо, здесь есть две возможности, на которые ссылаются? a()
или a(int c = 0)
с по умолчанию c=0
. Не уверен.
Если вы удалили статическое ключевое слово и вызвали функции типа obj.a()
, все равно была бы двусмысленность.
Парсер WRT LLVM
Я бы сказал, что для вас требуется какая-то дополнительная работа, которая не требуется стандартом, который должен был предполагать, что A::a()
является статическим.