为什么重载解析 select 指针类型为 0 而不是 1,而在任何一种情况下它都可以 select 省略?

Why does overload resolution select pointer type for 0 but not 1, when it could select ellipses in either case?

我有以下代码片段:

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: 

我的问题是:为什么重载解析 select evalvoid* 版本而不是 0... 版本,而不是 0 1?似乎在这两种情况下它都可以推断出参数是一个 int 并采用可变参数版本。

由于向后兼容,0 可转换为指针。它被用作 NULL 指针。现在用的是nullptr,但是0还是需要转换的,不然老代码就编译不下去了。

如果您在编译器中启用最高警告级别进行编译,编译器很可能会在 0 用作指针时向您发出警告。

int 八进制文字 0 可以隐式转换为 void* 指针类型,但 1 不能。这是 C++11 之前的东西(nullptr 及其类型 nullptr_t 是在 C++11 中引入的)并且会保留下来,否则现有代码会中断。

重载决议有利于非可变函数而不是可变函数。

把这两件事放在一起解释你的程序输出。

Why does overload resolution select the void* version of eval instead of the ... version for 0

因为0是空指针常量

but not for 1?

因为1不是空指针常量。

标准规则:

[conv.ptr]

A null pointer constant is an integer literal ([lex.icon]) with value zero or a prvalue of type std​::​nullptr_­t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type ...


It seems like in both cases it could infer that the argument is an int and take the variadic version.

C 风格的可变参数是重载决议中最不受欢迎的选择,即使它不需要转换另一个候选人所需的参数类型。只要有任何其他有效的候选人,其他候选人被选中。在这种情况下,存在 void* 重载,它对 0 有效但对 1 无效。

如果您有重载 eval(int),将为 0 和 1 选择重载。

P.S。这种 属性 C 风格可变参数的重载解析有时被黑暗模板魔术师用于实现类型特征。