动机:在P0288 std::move_only_function的实现中,我想为从move_only_function<int() noexcept>到move_only_function<int()>的转换编写一个不分配的特例。
move_only_function<int() noexcept> f = []() noexcept { return 42; };
move_only_function<int()> g = std::move(f); // should just copy the bits我想写,比如,
if constexpr (is_noexcept_version_of<HisSignature, MySignature>::value) { ... }我想实现这样的类型特性:
template<class, class>
struct is_noexcept_version_of : std::false_type {};
template<class Tp>
struct is_noexcept_version_of<Tp noexcept, Tp> : std::true_type {};但是没有一个供应商接受这一点;他们都认为Tp noexcept是语法错误。
问:如果不对部分专业进行组合爆炸,即不详尽地研究&、&&、const等所有可能的组合,你会如何写出这种类型特征?是否可以为is_noexcept_v<T>、add_noexcept_t<T>和remove_noexcept_t<T>编写简单的封闭类型特征?
发布于 2022-07-30 03:28:07
除了限定转换之外,指针到函数类型之间唯一可能的隐式转换是移除noexcept和类似于指针到成员函数的转换(基到派生转换除外),所以我认为下面的内容应该有效。
struct C {};
template<class A, class B>
struct is_noexcept_version_of : std::bool_constant<
requires {
requires std::is_convertible_v<A C::*, B C::*>;
requires std::is_function_v<A>;
requires !std::is_same_v<A, B>;
}> {};发布于 2022-08-02 19:18:35
你可以通过组合东西来减少组合混乱的长度。
template<class F>
struct function_info;
template<class R, class T, class...Args>
struct function_info<R (T::*)(Args...) const&&>:
function_helper< R(Args...), class_t<T>, const_v, rvalue_v >
{};
// ^^^^^ combinatorial explosion here ^^^^^
// You have to decompose the type into its independent dimensions, so
// you get 12 (24 if you want to support both methods and functions
// transparently).
template<class Sig, class T, auto constness, auto refness, auto exceptness >
struct function_helper:
base_properties<Sig, T, constness, refness, exceptness>
derived_properties<Sig, T, constness, refness, exceptness>
{};
template<class Sig, class T, auto constness, auto refness, auto exceptness >
using function_helper_t = typename function_helper<Sig, T, consteness, refness, exceptness>::type;
template<class Sig, class T, auto constness, auto refness, auto exceptness>
struct derived_properties {
using without_const = function_helper_t<Sig, T, no_const_v, refness, exceptness >;
using with_const = function_helper_t<Sig, T, const_v, refness, exceptness >;
// ... add/remove each property here. An add/remove for each dimension.
// This is the spot that this technique saves on lines
};
template<class Sig, class T, auto constness, auto refness, exceptness >
struct func_type;
// combinatorial explosion here:
template<class R, class...Args, class T>
struct func_type<R(Args...), T, const_v, rvalue_v, noexcept_v> {
using type = R(T::*) const&& noexcept;
};
// ^^^^^ You have to rebuild the type from the dimensional values, which
// means you get 2 * 3 * 2 = 12 different copy-pastas here ^^^
template<class Sig, class T, auto constness, auto refness, auto exceptness >
struct base_properties:
func_type<Sig, T, constness, refness, exceptness >
{
using sig_t = Sig;
using class_t = T;
constexpr auto const_v = constness;
constexpr auto ref_v = refness;
constexpr auto except_v = exceptness;
};这至少删除了组合爆炸中的一个层,即假设您想要对一组其他类型(noexcept、const、reference等)做同样的事情。
我们在一个地方分解类型,然后在另一个点重新组合,我们可以重用这些分解/重新组合。
https://stackoverflow.com/questions/73172543
复制相似问题