当使用文字 0
时在 C++ 中,编译器无法区分指针和 nullptr_t
函数的重载。
说明问题的代码:
struct Bar {};
void foo(Bar*) {
std::cout << "Bar*" << std::endl;
}
void foo(std::nullptr_t) {
std::cout << "nullptr_t" << std::endl;
}
TEST(NullPtrTest, ambiguity) {
foo(nullptr); // OK
foo(0); // ERROR
}
使用 Visual Studio 2019:error C2668: '`anonymous-namespace'::foo': ambiguous call to overloaded function
message : could be 'void `anonymous-namespace'::foo(std::nullptr_t)'
message : or 'void `anonymous-namespace'::foo(`anonymous-namespace'::Bar *)'
message : while trying to match the argument list '(int)'
使用 GCC 9:Test.cpp: In member function ‘virtual void {anonymous}::NullPtrTest_ambiguity_Test::TestBody()’:
Test.cpp:425:8: error: call of overloaded ‘foo(int)’ is ambiguous
425 | foo(0); // ERROR
| ^
Test.cpp:415:6: note: candidate: ‘void {anonymous}::foo({anonymous}::Bar*)’
415 | void foo(Bar*) {
| ^~~
Test.cpp:419:6: note: candidate: ‘void {anonymous}::foo(std::nullptr_t)’
419 | void foo(std::nullptr_t) {
| ^~~
有什么好的方法来解决这个问题?我不想做的事情:
0
带有 nullptr
的文字到处。我们的遗留代码库中的实例太多了。 int
或 long
(或类似的)过载。由于0
将是唯一有效的整数值,您必须添加运行时检查,这会很丑陋。 nullptr_t
重载并在运行时检查指针重载中的值。这行得通,并不可怕,但它阻止了我们对空常量进行优化的实现。 谢谢!
说明:
constexpr
nullptr
时执行或 0
用来。一般的指针实现仍然需要检查空值。 nullptr_t
重载并不是真正必要的,但它会很好。 最佳答案
模板不在排除列表中 - 使其成为模板,仅限于接受 Bar*
:
#include <iostream>
#include <type_traits>
struct Bar {};
template <typename T>
typename std::enable_if<std::is_same_v<T, Bar>>::type foo(T*) {
std::cout << "Bar*\n";
}
void foo(std::nullptr_t) {
std::cout << "nullptr_t\n";
}
int main() {
Bar b;
foo(nullptr);
foo(0);
foo(&b);
}
我想在实践中你的Bar*
可能会传递派生类型,即,您可能需要 std::enable_if
中的不同条件.如果 foo(Bar*)
有点实质性,您可能不想在 header 中实现。但是,由于无论如何只有一个实例,您可以将实现放入 .cpp
文件并显式实例化它,或者,分派(dispatch)给一个实现函数。
关于c++ - 有没有解决 nullptr_t 和指针重载之间歧义的好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65419576/