Reputation: 331
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;
Upvotes: 0
Views: 203
Reputation: 63114
To solve this, we need T
to:
<<
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;
Upvotes: 1
Reputation: 11250
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; }
Upvotes: 0