Как связать c ++ std :: function с функцией шаблона? - PullRequest
0 голосов
/ 07 января 2019

существует ли какой-либо механизм, который можно использовать для реализации кода следующим образом:

// T can be any type
std::function<T(int,int)> tf;

tf = [](int x, int y) -> int{
    return x + y;
};

cout << tf(4, 5) << endl;

tf = [](int x, int y) -> string{
    return "hello world";
}
cout << tf(4,5) << endl;

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Чтобы решить эту проблему, нам нужно T:

  • Уметь стирать и хранить экземпляр произвольного типа;
  • быть конвертируемым из такого экземпляра;
  • Перегрузите оператор << и динамически перенаправьте его на экземпляр со стертым типом.

В зависимости от того, ограничен ли ваш список возможных типов или нет, мы можем отложить большую часть тяжелой работы до boost::variant или boost::any (соответственно std::variant или std::any в C ++ 17 и выше) .

Версия variant проста:

template <class... Ts>
struct StreamableVariant : boost::variant<Ts...> {
    using boost::variant<Ts...>::variant;

    friend decltype(auto) operator << (std::ostream &os, StreamableVariant const &sv) {
        return boost::apply_visitor([&](auto const &o) -> decltype(auto) {
            return os << o;
        }, sv);
    }
};

// Usage
std::function<StreamableVariant<int, std::string>(int,int)> tf;

Версия any немного сложнее, поскольку нам нужно вручную стереть функциональность потоковой передачи, пока мы еще знаем тип объекта во время создания:

struct StreamableAny : boost::any {
    template <class T>
    StreamableAny(T &&t)
    : boost::any{std::forward<T>(t)}
    , _printMe{[](std::ostream &os, StreamableAny const &self) -> decltype(auto) {
        return os << boost::any_cast<T const &>(self);
    }}{ }

private:
    friend std::ostream &operator << (std::ostream &os, StreamableAny const &sa) {
        return sa._printMe(os, sa);
    }

    std::ostream &(*_printMe)(std::ostream &os, StreamableAny const &);
};

// Usage
std::function<StreamableAny(int,int)> tf;
0 голосов
/ 07 января 2019

Вы не можете назначить вызываемый объект с типом возврата, отличным от того, который изначально использовался в std::function, если только первый неявно конвертируется во второй. Оператор присваивания не будет кандидатом .

В другом случае типы возвращаемых данных могут отличаться, и это когда тип возвращаемого объекта std::function равен void:

std::function<void(int)> f = [](int) -> int { return 0; }
...