尝试使用尾随返回类型为

时间:2019-08-13 13:28:06

标签: c++ sfinae

我在SO上看到了答案,这些答案解释了SFINAE为什么不适用于lambda返回类型。我对设计进行了一些更改,但是现在收到一个甚至更陌生的错误。我不知道我想念什么。代码将使用C ++ 11、14和17进行编译。我有一个与C ++ 17兼容的apply

#include <algorithm>
#include <vector>
#include <functional>
#include <tuple>
#include <utility>

template <typename ...T>
struct S {
  std::vector<std::tuple<T...>> things;
  template <typename F>
  typename std::enable_if<std::is_same<
    typename std::invoke_result<
      std::apply<F, T...>, F, T...>::type, bool>::value,
      bool>::type
  find_if(const F &f) {
      return std::any_of(things.begin(), things.end(),
      [&](const std::tuple<T...> &t) {
          return std::apply(f, t);
      });
  }
  template <typename F>
  auto find_if(const F &f) -> decltype(std::declval<F>()(things.front())) {
      return std::any_of(things.begin(), things.end(),
      [&](const std::tuple<T...> &t) { return f(t); });
  }
};

void f() {
    S<int, float> s;
    auto l = [](const std::tuple<int, float> &) -> bool { return false; };
    s.find_if(l);
}

我的目的是调用正确的谓词。如果谓词具有类型为std::tuple<Ts...>的单个参数,则直接调用它。如果谓词参数列表与解压缩的模板参数包匹配,请调用该参数包。

GCC和Clang都抱怨第一种方法apply不是类型。

<source>:13:26: error: type/value mismatch at argument 1 in template parameter list for 'template<class _Functor, class ... _ArgTypes> struct std::invoke_result'
   13 |       std::apply, F, T...>::type, bool>::value,
      |                          ^
<source>:13:26: note:   expected a type, got 'std::apply'

1 个答案:

答案 0 :(得分:1)

元函数std::invoke_result期望可调用的东西以及参数的类型为第一个参数。

不幸的是,std::apply不是类型,而是函数。另外,std::apply可以使用类型推导,因此对Sfinae不友好。

解决方案是使用可调用对象的类型,而不是应用调用。

template <typename ...T>
struct S {
    std::vector<std::tuple<T...>> things;

    template <typename F, typename std::enable_if_t<
        std::is_same_v<std::invoke_result_t<F, T...>, bool>, int> = 0>
    auto find_if(const F &f) -> bool {
        return std::any_of(things.begin(), things.end(),
        [&](const std::tuple<T...> &t) {
            return std::apply(f, t);
        });
    }
};

此外,您的lambda应该如下所示:

[](int, float) -> bool { return false; };

这是因为apply正在分解元组。