Почему разрешение перегрузки выбирает тип указателя для 0, а не 1, когда он может выбрать эллипсы в любом случае? - PullRequest
5 голосов
/ 04 марта 2020

У меня есть следующий фрагмент кода:

void eval(void*) { std::cout << "hello world\n"; }
void eval(...) { }
int main(int argc, char *argv[])
{
    std::cout << "0: "; eval(0);
    std::cout << "1: "; eval(1);
    return 0;
}

, который дает вывод:

0: hello world
1: 

Мой вопрос: почему разрешение перегрузки выбирает версию void* eval вместо ... версии для 0, но не для 1? Похоже, что в обоих случаях можно сделать вывод, что аргумент является целым числом, и принять переменную c версию.

Ответы [ 3 ]

7 голосов
/ 04 марта 2020

Из-за обратной совместимости 0 конвертируется в указатель. Он использовался как указатель NULL. В настоящее время используется nullptr, но 0 все еще должен быть конвертируемым, иначе старый код больше не будет компилироваться.

Если вы компилируете с самым высоким уровнем предупреждения, включенным в вашем компиляторе, скорее всего, компилятор предупредит Вы всякий раз, когда 0 используется в качестве указателя.

4 голосов
/ 04 марта 2020

Почему разрешение перегрузки выбирает vval * версию eval вместо ... версии для 0

Поскольку 0 является константой нулевого указателя.

но не для 1?

Поскольку 1 не является константой нулевого указателя.

Стандартное правило:

[conv.ptr]

Константа нулевого указателя - это целочисленный литерал ([lex.icon]) со значением ноль или значением типа std :: nullptr_t. Константа нулевого указателя может быть преобразована в тип указателя; результатом является значение нулевого указателя этого типа ...


Кажется, что в обоих случаях это может означать, что аргумент является целым и принимает переменную c версия.

Аргумент C -style variadi c является наименее предпочтительным выбором по разрешению перегрузки, даже если для него не требуется преобразование типа аргумента, которое потребуется другому кандидату. Пока есть любой другой действительный кандидат, другой кандидат выбран. В этом случае существует перегрузка void*, которая действительна для 0, но не для 1.

Если у вас была перегрузка eval(int), она будет выбрана как для 0, так и для 1.

PS Это свойство разрешения перегрузки аргументов C -style variadi c иногда используется для реализации черт типа магами темных шаблонов.

4 голосов
/ 04 марта 2020

Восьмеричный литерал int 0 неявно преобразуется в тип указателя void*, а 1 - нет. Это вещь до C ++ 11 (nullptr и ее тип nullptr_t были введены в C ++ 11) и здесь, чтобы остаться, иначе существующий код сломается.

Разрешение перегрузки предпочитает не -variadi c функция над переменной c one.

Соединение этих двух вещей объясняет вывод вашей программы.

...