创建一个重载集 class 依赖于 std::invoke 和 classical 重载解析规则

Create an overload set class relying on std::invoke with classical overload resolution rules

我想设计一个class:

template <class... F> class overload_set;

将在构造时采用可调用列表,并且将有一个 operator() 将应用 classical 重载决议规则来决定调用哪个函数。

对于两个函数,这将是这样的:

template <class F0, class F1>
struct overload_set: F0, F1
{
    constexpr overload_set(F0 f0, F1 f1): F0(f0), F1(f1) {}
    using F0::operator();
    using F1::operator();
};

但是,这只适用于函数对象,而我希望它适用于任何使用 std::invoke 的可调用对象(自由函数、仿函数、lambda、函数成员、成员...)。我当然希望它能够处理函数成员的 ref/const 限定的所有子项,例如:

struct subtle
{
    constexpr void operator()() noexcept {}
    constexpr void operator()() & noexcept {}
    constexpr void operator()() && noexcept {}
    constexpr void operator()() const& noexcept {}
    constexpr void operator()() const&& noexcept {}
};

如果将 subtle 传递给 overload_set,它应该可以正常工作。

是否有可能在 C++17 中创建这样的 class overload_set,如果可以,如何创建(根据需要使用尽可能多的模板元编程技巧,但尽可能少的 C 宏(希望 none))?

实现@KerrekSB 所说的

template<typename F>
struct functor
{
    using type = F;
};

template<bool Noexcept, typename R, typename... Args>
struct functor<R (*)(Args...) noexcept(Noexcept)>
{
    struct fn
    {
        R (*p)(Args...) noexcept(Noexcept);
        R operator()(Args&&... args) const noexcept(Noexcept)
        {
            return p(std::forward<Args>(args)...);   
        }
    };
    using type = fn;
};

template<typename F>
using func = typename functor<std::decay_t<F>>::type;

template<typename... Fs>
struct over : func<Fs>...
{
    template<typename... Gs>
    over(Gs&&... gs) : func<Fs>{std::forward<Gs>(gs)}... {}

    using func<Fs>::operator()...;
};

template<typename... Gs>
auto makeover(Gs&&... gs)
{
    return over<func<Gs>...>{std::forward<Gs>(gs)...};   
}

你把它当作

int main()
{
    auto o = makeover([](int){ std::cout << "int\n"; }, 
                     +[](double){ std::cout << "double\n"; });
    o(42);    // prints int
    o(42.0);  // prints double

    auto o2 = makeover(+[]() noexcept {});
    std::cout << noexcept(o2());  // prints 1
}

Demo