Вернуть std :: function с автоматическим типом возврата - PullRequest
2 голосов
/ 06 августа 2020

Я хочу создать функтор для преобразования 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 здесь.

Кто-нибудь может предложить способ сделать это, пожалуйста?

Ответы [ 2 ]

4 голосов
/ 06 августа 2020

Тип возврата должен быть одинаковым и фиксированным для одной функции или одного экземпляра шаблона функции. Вы можете сделать шаблон функции как

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, если , ненужный оператор будет быть отброшенным во время компиляции.

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&. И лямбда, похоже, не нуждается в каких-либо захватах.

2 голосов
/ 06 августа 2020

Я не думаю, что возможно автоматическое определение типа возврата в std::function.

Если вам нужно сохранить лямбда / функтор, который вызывает функцию std::sto*, я придумал с некоторыми альтернативами. Просто создайте сам шаблон и замените им auto. Это позволяет удалить параметр типа const std::string&.

#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
    
}

Я бы посоветовал просто вызвать правильную функцию преобразования numeri c вместо сохранения лямбда / функтора, вызывающего std::sto*, было бы лучшим подходом.

...