有没有什么好的方法可以解决nullptr_t和指针重载之间的歧义?

Is there a good way to resolve the ambiguity between nullptr_t and pointer overloads?

在 C++ 中使用文字 0 时,编译器无法区分函数的指针和 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) {
      |      ^~~

解决这个问题的好方法是什么?

我不想做的事情:

谢谢!

澄清:

模板不在排除列表中 - 将其设为模板,限制为仅接受 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 文件并显式实例化它,或者分派给实现函数。