在 C++ 中将 void 作为 labmda 的通用返回类型干净地处理

Lub*_*und 0 c++ generics lambda

我正在尝试编写这样的函数:

template <typename T>
void testActionBehavesIdentically(Foo& fooA, Foo& fooB, std::function<T(Foo&)> action)
  if (std::is_same<T, void>::value)
  {
    // perform action even if T is void
    action(fooA);
    action(fooB);
  }
  else
  {
    // if T is not void, test also return values
    T resultA = action(fooA);
    T resultB = action(fooB);
    CHECK_EQUAL(resultA, resultB);
  }
  // tests that the state of both foos is the same
  CHECK_EQUAL(fooA, fooB);
}
Run Code Online (Sandbox Code Playgroud)

T有时在哪里void。编译(在 VS2019 上)失败并显示 error C2182: 'resultA': illegal use of type 'void'. 有没有干净的方法?(希望能在大多数标准编译器中编译)?谢谢你。

mat*_*ord 5

现在发生的事情是编译器仍然会编译两个if分支(因为它实际上不知道在运行时之前会调用哪个)。这会导致失败,因为其中一个分支没有正确编译。有几个修复(来自评论):

如果您的编译器支持它,这将是一种选择:

  if constexpr (std::is_same<T, void>::value) {
    // perform action even if T is void
    action(fooA);
    action(fooB);
  } else {
    ...
  }
Run Code Online (Sandbox Code Playgroud)

这实际上只会根据 T 的类型编译一个分支。

如果您的编译器不支持它,这是另一种选择:

template <typename T>
void testActionBehavesIdentically(Foo& fooA, Foo& fooB, std::function<T(Foo&)> action) {
    // check assuming T != void
}

// overload which will be called if T was void
void testActionBehavesIdentically(Foo& fooA, Foo& fooB, std::function<void(Foo&)> action) {
    // check assuming T == void
}
Run Code Online (Sandbox Code Playgroud)

当 T 为 void 时,编译器将匹配重载,而不是分派到函数的通用版本。在这里你甚至可以说“如果 T 是int做一些不同的事情”,这有点整洁(但可能会变得混乱)。

  • FWIW,你不应该专注,而应该超载。其一,打字更少,更容易阅读。其次,函数模板特化是 C++ 中的二等公民,并且具有令人困惑的规则。这是关于该主题的精彩视频,详细介绍了标准库函数的函数模板专业化已被删除的一些原因:https://www.youtube.com/watch?v=NIDEjY5ywqU (5认同)