【问题标题】:Return a std::function with auto return type返回具有自动返回类型的 std::function
【发布时间】:2020-11-26 09:13:34
【问题描述】:

我想创建一个仿函数来将 std::string 转换为不同的类型。

std::function<auto(const std::string)> create(const std::string &type)
{
  if(type=="int") {
    return [&](const std::string &value){return std::stoi(value);}
  } else if(type=="float") {
    return [&](const std::string &value){return std::stof(value);}
  }  else {
    throw std::runtime_error("");
  }
}

但似乎我们不能在这里使用 auto 作为 std::function 的返回类型。

有人可以建议一种方法吗?

【问题讨论】:

  • 你真正想做什么?您愿意使用模板和模板专业化吗?
  • 我有一些不同类型的数据作为字符串。所以需要铸造它们。我可以使用模板

标签: c++ types return auto std-function


【解决方案1】:

对于一个函数或函数模板的一个实例化,返回类型必须相同且固定。您可以将函数模板设为

template <typename R>
std::function<R(const std::string&)> create()
{
  if(std::is_same<R, int>::value) {
    return [](const std::string &value){return std::stoi(value);};
  } else if(std::is_same<R, float>::value) {
    return [](const std::string &value){return std::stof(value);};
  }  else {
    throw std::runtime_error("");
  }
}

然后像这样使用它

auto f_int = create<int>();
auto f_float = create<float>();

由于 C++17 可以使用constexpr if,不必要的语句将在编译时被丢弃。

template <typename R>
std::function<R(const std::string&)> create()
{
  if constexpr (std::is_same_v<R, int>) {
    return [](const std::string &value){return std::stoi(value);};
  } else if constexpr (std::is_same_v<R, float>) {
    return [](const std::string &value){return std::stof(value);};
  }  else {
    throw std::runtime_error("");
  }
}

BTW:作为返回类型,std::function 的参数应该是const std::string&amp;。而且 lambda 似乎不需要捕获任何东西。

BTW2:根据您使用返回值的方式,直接返回 lambda 而不是将其包装到 std::function 中也可能就足够了。

template <typename R>
auto create()
{
  if constexpr (std::is_same_v<R, int>) {
    return [](const std::string &value){return std::stoi(value);};
  } else if constexpr (std::is_same_v<R, float>) {
    return [](const std::string &value){return std::stof(value);};
  }  else {
    throw std::runtime_error("");
  }
}

【讨论】:

  • 该参数现已废弃
  • 这样不行。我拥有的类型信息和值实际上都是字符串格式。所以我必须首先检查类型字符串以制作适当的转换函子,然后使用它将值字符串转换为适当的类型
  • @shaaa 因此,您希望在运行时根据字符串的内容更改返回类型。然后你必须使用@SimonKraemer 评论的std::variantstd::any 之类的东西。而且即使函数返回,你也必须知道确切的类型,否则你无法从中获取值。
【解决方案2】:

我认为不可能在 std::function 中进行自动返回类型扣除。

如果您需要存储调用 std::sto* 函数的 lambda/functor,我想出了一些替代方案。只需自己创建一个模板并用它替换auto。这允许您删除const std::string&amp; 类型参数。

#include <type_traits> // for std::is_same

template <typename T = int>
constexpr std::function<T(const std::string)> create()
{
    if (std::is_same<T, int>::value)   
    { return [&](const std::string &value) { return std::stoi(value); }; }

    if (std::is_same<T, float>::value) 
    { return [&](const std::string &value) { return std::stof(value); }; }

    throw std::runtime_error("");
}

或者你可以自己创建一个仿函数类。

#include <type_traits> // for std::is_same

template <typename T = int>
struct Functor {

    T operator()(const std::string& input) {
        if (std::is_same<T, int>::value)   { return std::stoi(input); };
        if (std::is_same<T, float>::value) { return std::stof(input); };
        throw std::runtime_error("");
    }

};

上述用途。

int main() {
    
    auto f_i = create();
    auto f_f = create<float>();
    f_i("42");   // returns an int
    f_f("3.14"); // returns a float
    
    Functor fo_i;
    Functor<float> fo_f;
    fo_i("42");   // returns an int
    fo_f("3.14"); // returns a float
    
}

我建议简单地调用正确的数值转换函数而不是存储调用 std::sto* 的 lambda/functor 会是更好的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-06
    • 1970-01-01
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多