为什么 boost::hana::overload_t 不能成为 class 的成员

Why can't boost::hana::overload_t be a member of a class

所以我有几个函数,我得到了一个魔法函数对象,它提供了重载解析:

void foo1();
void foo2(int);


auto foo_ptr = boost::hana::overload(foo1,foo2);
//Later
foo_ptr(12);  //Both Valid (Yeah!)
foo_ptr();

但是当我这样做时,问题就出现了:

using ptr_t = decltype(foo_ptr);

struct mine
{
    ptr_t ptr;
    mine(ptr_t ptr) : ptr(ptr){}
};


mine m(foo_ptr);

当我尝试编译这段代码时,我得到 error: no matching function for call to 'boost::hana::overload_t<void (*)(int)>::overload_t()'

godbolt 上亲自查看......

现在我的问题是:

我是否可以复制这些重载对象(hana 的文档没有说明任何一种方式),如果可以,为什么当我将它作为成员放入 class 时它会失败?

这可以说是 Boost.Hana 中的错误。 overload_t 的构造函数是:

template <typename F_, typename ...G_>
constexpr explicit overload_t(F_&& f, G_&& ...g)
    : overload_t<F>::type(static_cast<F_&&>(f))
    , overload_t<G...>::type(static_cast<G_&&>(g)...)
{ }

请注意,这些是不受约束的转发引用。这是一个常见的问题,当你有一个非常量对象时,转发引用构造函数比复制构造函数更匹配。简化示例:

struct X {
    X();
    template <typename F> X(F&&); 
    X(X const&) = default;
};

X x1;
X x2(x1); // does *not* call the copy constructor

但是,如果对象是 const,那么复制构造函数会更好。所以简短的解决方法就是这样做:

struct mine
{
    ptr_t ptr;
    mine(ptr_t const& ptr) : ptr(ptr){}
};

现在可以编译了。同样,正如 Yakk 所建议的那样,出于同样的原因,移动而不是复制也可以工作:

struct mine
{
    ptr_t ptr;
    mine(ptr_t ptr) : ptr(std::move(ptr)) {}
};