【问题标题】:Overload regardless noexcept specification重载,不管 noexcept 规范
【发布时间】:2020-03-25 15:35:31
【问题描述】:

我必须提供一个f 的重载集,它同时接受成员和成员函数指针:

void g(int) {}

template <typename T, typename Field>
void f(const T& t, Field T::*field) { g(t.*field); }

template <typename T, typename Field>
void f(const T& t, Field (T::*getter)() const) { g((t.*getter)()); }

struct Foo {
  int x = 0;
  int y() const noexcept { return 1; }
};

int main() {
  const Foo foo;
  f(foo, &Foo::x);
  f(foo, &Foo::y);
}

这在 C++11 和 C++14 中运行良好,但在 C++17 中中断,因为从 P0012R1 开始,noexcept 说明符是函数类型的一部分。为了解决这个问题,必须添加一个额外的重载:

#if __cplusplus >= 201703L

template <typename T, typename Field>
void f(const T& t, Field (T::*getter)() const noexcept) { g((t.*getter)()); }

#endif

宏守卫是必要的,否则代码无法使用旧标准编译,例如 C++11 或 C++14(错误是关于重新定义函数模板)。

如上所示,两个重载的实现是一样的。是否可以提供在 C++14 和 C++17 中工作的单个重载,而无需条件编译 (#if/endif)?目标是减少复杂性、代码重复和测试负担。

实际用例:https://github.com/Morgan-Stanley/binlog/pull/59/files#diff-043a057ac0b43822d0084562ace76697

【问题讨论】:

    标签: c++ templates c++17 generic-programming


    【解决方案1】:

    是的。只需写一个重载,总计,然后使用std::invoke:

    template <typename T, typename F>
    void f(const T& t, F f) { g(std::invoke(f, t)); }
    

    虽然std::invoke 本身是 C++17,但它可以在 C++11 中实现——而且它可能只是值得做的,因为它通常很有用。这种方法不仅可以处理 C++17 中的 noexcept 成员函数,还可以处理 C++11 中的引用限定和非 const 限定的成员函数。

    虽然 C++11 本身也包含 std::invoke 的实现——只是在一个意想不到的地方:std::reference_wrapper&lt;T&gt;:

    template <typename T, typename F>
    void f(const T& t, F f) { g(std::ref(f)(t)); }
    

    【讨论】:

      猜你喜欢
      • 2014-07-09
      • 2021-11-03
      • 2015-10-04
      • 2019-03-29
      • 2017-10-01
      • 2010-09-30
      • 1970-01-01
      • 2020-02-22
      相关资源
      最近更新 更多