【问题标题】:Take generic lambda return type into consideration for SFINAE为 SFINAE 考虑通用 lambda 返回类型
【发布时间】:2021-10-21 11:16:54
【问题描述】:

我想要一个接受通用 lambda 的函数,但我需要根据 lambda 的返回类型略有不同的逻辑。例如,我想做如下的事情(这是一个人为的例子):

template<typename F>
void foo(F &&function) {
    auto result = function();
    // Have different behavior based on `result`'s type.
}

为了方便起见,我想我可以使用 SFINAE。在我看来,这看起来像:

template<typename F,
         typename std::enable_if_t<???>>
void foo(F &&function) {

}

有人知道如何根据F 的返回类型启用/禁用方法吗?

【问题讨论】:

标签: c++ templates lambda sfinae


【解决方案1】:

您不需要为此使用 SFINAE。正如评论中提到的,您可以根据不同重载的返回类型编写不同的逻辑,然后调用该重载集

void f(int); // do the logic for an int
void f(double); // do the logic for a double
// ... and so on

template<typename F>
void foo(F &&function) 
{
    auto result = function();
    f(result); // get different behavior based on `result`'s type.
}

如果逻辑需要返回值以外的其他数据,您需要将其传递给帮助程序f


为避免这种情况,并将所有逻辑放在一个位置,您可以在返回值的类型上编写一个编译时“开关”

template<typename F>
void foo(F &&function) 
{
    auto result = function();
    if constexpr (std::is_same_v<decltype(result), int>)
      // logic for an int
    else if constexpr (std::is_same_v<decltype(result), double>)
      // logic for a double
    else
      // ... and so on
}

请注意,这两个选项完全等效,即由于隐式转换等因素,重载解析在所有情况下的行为可能与is_same不完全相同,因此您必须那里要小心一点。一个解决方法是为第一个版本编写一个重载,以捕获除精确转换之外的所有内容

template<typename T>
void f(T) = delete;

这将更接近第二个版本。

【讨论】:

  • Nitpick:两者并不是“相当”等价的,尤其是对于 intdouble 这样的类型,因为可能需要也可能不需要进行卑鄙的隐式转换。
  • @Frank 好点,我在最后添加了一个小警告。我不想在这里过多地介绍,但这应该足够了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-21
  • 2011-03-04
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多