创建一个重载集 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
}
我想设计一个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
}