C++ std::函数如何绑定到模板函数

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

本文关键字:函数 绑定 std 何绑定 C++      更新时间:2023-10-16

是否有任何机制可用于实现如下代码:

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

要解决这个问题,我们需要T

  • 能够类型擦除并保存任意类型的实例;
  • 可从此类实例转换;
  • 重载<<运算符并将其动态转发到类型擦除的实例。

根据您的可能类型列表是否有界,我们可以将大部分繁重的工作推迟到boost::variantboost::any(分别是std::variantstd::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;

不能分配返回类型与std::function中最初使用的返回类型不同的可调用对象,除非前者可隐式转换为后者。赋值运算符将不是候选项。

还有另一种情况,返回类型可能不同,当std::function对象的返回类型void时:

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