c++ 从std::函数的返回类型推导模板参数

91zkwejq  于 2023-01-15  发布在  其他
关注(0)|答案(2)|浏览(178)

我通常不写C++,今天我尝试了C++模板,我实现了一个Maybe类型,看起来像这样

#include <functional>
#include <iostream>
#include <string>
template<typename T>
class TMaybe
{
  T value;
public:
  TMaybe() : value(nullptr){}
  TMaybe(T &&v) : value(v){}
  TMaybe(T v) : value(v){}
};

template<typename T, typename R>
TMaybe<R> maybe_if(const TMaybe<T> &m, std::function<R(T v)> f){
  return (m.value != nullptr) ? TMaybe<R>(f(m)) : TMaybe();
}

int main(){
  int i = 10;
  auto m = TMaybe<int>(i);
  auto plus_ten = [](int i) -> int {return i + 10;};
  maybe_if(m, plus_ten); // could not deduce template argument for 'std::function<R(T)>' from 'main::<lambda_17413d9c06b6239cbc7c7dd22adf29dd>'
}

但是错误消息could not deduce template argument for 'std::function<R(T)>' from 'main::<lambda_17413d9c06b6239cbc7c7dd22adf29dd>'没有太大帮助,你能发现这个错误吗?

icnyk63a

icnyk63a1#

编译器只能从f推导出R,如果你传递给它一个std::function<R(T)>的实际示例;传递lambda是行不通的,因为lambda不是std::function特殊化的示例。
编写代码的正确方法是允许任何函子类型,并从中推导出R

template<typename T, typename F, typename R = typename std::result_of<F(T)>::type>
TMaybe<R> maybe_if(const TMaybe<T> &m, F f){
  return (m.value != nullptr) ? TMaybe<R>(f(m.value)) : TMaybe();
}
56lgkhnf

56lgkhnf2#

模板参数推导发生在Lambda到std::fucntion的隐式转换之前。
类型推导不考虑隐式转换(上面列出的类型调整除外):这是overload resolution的工作,稍后会执行。
因此编译器只能从“f“(函子)推导出“R“(返回类型),如果你传递一个std::function<R(T)>类型的实际示例。

C++20示例(可能更高版本)

使用std::type_identity_t,例如:

#include <type_traits>

// ...

template<typename T, typename R>
TMaybe<R> maybe_if(const TMaybe<T> &m, std::function< std::type_identity_t<R> (T v)> f)
{
  return (m.value != nullptr) ? TMaybe<R>(f(m)) : TMaybe();
}

旧编译器示例

如果你的项目不允许C++20,你需要把函数类型作为模板参数,并从那里推导出R

对于MSVC 2015,请使用std::result_of

template<typename T, typename F, typename R = typename std::result_of<F(T)>::type>
TMaybe<R> maybe_if(const TMaybe<T> &m, F f)
{
  return (m.value != nullptr) ? TMaybe<R>(f(m.value)) : TMaybe();
}

对于MSVC 2010,请使用decltype

MSVC 2010有std::result_of,但不允许函数使用默认模板参数,因此我们做了如下操作:

#define MY_RESULT_OF(functor, argType) decltype( functor(*static_cast<argType * >(nullptr)) )

template<typename T, typename F>
auto maybe_if(const TMaybe<T> &m, F f) -> TMaybe< MY_RESULT_OF(f, T) >
{
  typedef MY_RESULT_OF(f, T) R;
  return (m.value != nullptr) ? TMaybe<R>(f(m.value)) : TMaybe();
}

相关问题