简体   繁体   中英

how c++ std::function bind to a template function?

is there any mechanism that can be used to implement code as follows:

// 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;

To solve this, we need T to:

  • Be able to type-erase and hold an instance of arbitrary type;
  • Be convertible from such an instance;
  • Overload the << operator and forward it to the type-erased instance dynamically.

Depending on whether your list of possible types is bounded or not, we can defer much of the heavy lifting to either boost::variant or boost::any (respectively std::variant or std::any in C++17 and above).

The variant version is straightforward:

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;

The any version is a bit more involved, as we need to type-erase the streaming functionality manually while we still know the object's type at construction time:

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;

You can't assign a callable with a return type different from the one initially used in the std::function unless the former is implicitly convertible to the latter. The assignment operator will not be a candidate .

There is another case in which the return types can differ and is when the return type of the std::function object is void :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM