【问题标题】:deduce return type of lambda with arguments用参数推断 lambda 的返回类型
【发布时间】:2020-11-05 14:53:12
【问题描述】:

是否可以在不提供参数类型的情况下推断 lambda 函数的返回类型(C++14)? 假设返回类型不依赖于参数 (即排除f_auto()等情况)。

到目前为止,我已经尝试根据参数类型推断返回类型。

// main.cpp

#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <utility>

// Deduces the return type of Func() called with Args, void if invalid.
// Case of no arguments.
template <class Func, class... Args>
class ResultOf {
 private:
  template <class>
  static void Eval(...);
  template <class U>
  static auto Eval(decltype(std::declval<U>()())* r) {
    return *r;
  }

 public:
  using type = decltype(Eval<Func>(0));
};

// Case of one or more arguments.
template <class Func, class T, class... TT>
struct ResultOf<Func, T, TT...> {
 private:
  template <class...>
  static void Eval(...);
  template <class U, class... UU>
  static auto Eval(decltype(std::declval<Func>()( //
      std::declval<U>(), std::declval<UU>()...))* r) {
    return *r;
  }

 public:
  using type = decltype(Eval<T, TT...>(0));
};

template <class... Args, class Func>
std::string GetReturnType(Func func) {
  using type = typename ResultOf<Func, Args...>::type;
  return typeid(type).name();
}

#define P(func, ...)                                                 \
  do {                                                               \
    std::cout << (#func) << '(' << (#__VA_ARGS__) << ')' << "  ->  " \
              << GetReturnType<__VA_ARGS__>(func) << std::endl;      \
  } while (0)

int main() {
  auto f_void = []() { return 0; };
  auto f_int = [](int a) { return a; };
  auto f_int_double = [](int a, double b) { return a + b; };
  auto f_auto = [](auto a) { return a; };

  P(f_void);
  P(f_int, int);
  P(f_int, double);
  P(f_int_double, int, double);
  P(f_int_double, int, int);
  P(f_auto, int);
  P(f_auto, double);
}

输出

$ g++ -std=c++14 main.cpp -o main
$ ./main | c++filt -t
f_void()  ->  int
f_int(int)  ->  int
f_int(double)  ->  int
f_int_double(int, double)  ->  double
f_int_double(int, int)  ->  double
f_auto(int)  ->  int
f_auto(double)  ->  double

更新:基于@igortandetnik 回答的解决方案

// Deduces the return type of `Func::operator() const` if unambiguous.
template <class Func>
class ResultOfDeducedArgs {
 private:
  template <class...>
  static void Eval(...);
  template <class R, class... Args>
  static R Ret(R (Func::*)(Args...) const);
  template <class T>
  static auto Eval(decltype(Ret(&T::operator()))* r) {
    return *r;
  }

 public:
  using type = decltype(Eval<Func>(0));
};

输出

f_int()  ->  int
f_int_double()  ->  double
f_auto()  ->  void

【问题讨论】:

  • f_auto是多态恒等函数,可以称为f_ident;顺便说一句,f_auto(f_auto) 的类型呢?另见type inferencewikipage
  • 你用这个做什么?当然只是明确地写出返回类型应该可以工作....
  • @Evg 这需要 C++17
  • @CoffeeTableEspresso 我需要将此 lambda 传递给模板函数,其逻辑取决于返回类型

标签: c++ lambda c++14


【解决方案1】:

如果您愿意将自己限制为非泛型 lambda(并且通常仅限于只有一个 operator() 重载的类对象),那么这样的东西应该可以工作(未经测试):

template <typename T, typename R, typename... Args>
R ResultOf(R (T::*)(Args...));

用作

using R = decltype(ResultOf(&decltype(my_lambda)::operator()));

这可以包装在帮助类中以获得更好的语法;我们将此作为练习留给读者。

【讨论】:

  • 使用非mutable lambdas 应该是R ResultOf(R (T::*)(Args...) const);
  • @igortandetnik,@Evg 这行得通,谢谢;需要R ResultOf(R (T::*)(Args...) const);;添加到原始问题中
猜你喜欢
  • 1970-01-01
  • 2017-10-15
  • 1970-01-01
  • 2021-10-23
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
  • 1970-01-01
  • 2019-12-06
相关资源
最近更新 更多