我有一些POD struct foo
;假设它是struct foo { int x; unsigned y; }
。我希望能够使用词典顺序比较struct foo
- 当然是按照他们的字段顺序。也就是说,我希望所有运算符<,==,>等适用于struct foo
的
我是否可以通过某种通用方式执行此操作,而无需使用任何reflection voodoo修饰我的结构定义 - 而且不会拼写出所有这些运算符定义?或者是否能够做出太多“语言反映依赖”期望?
答案 0 :(得分:5)
您可以在C ++ 1z中执行此操作。基于this答案,我准备了以下概念证明:
struct anything {
template<class T> operator T()const;
};
namespace details {
template<class T, class Is, class=void>
struct can_construct_with_N:std::false_type {};
template<class T, std::size_t...Is>
struct can_construct_with_N<T, std::index_sequence<Is...>,
std::void_t< decltype(T{(void(Is),anything{})...}) >>:
std::true_type
{};
}
template<class T, std::size_t N>
using can_construct_with_N=details::can_construct_with_N<T, std::make_index_sequence<N>>;
namespace details {
template<std::size_t Min, std::size_t Range, template<std::size_t N>class target>
struct maximize: std::conditional_t<
maximize<Min, Range/2, target>{} == (Min+Range/2)-1,
maximize<Min+Range/2, (Range+1)/2, target>,
maximize<Min, Range/2, target>
>{};
template<std::size_t Min, template<std::size_t N>class target>
struct maximize<Min, 1, target>: std::conditional_t<
target<Min>{},
std::integral_constant<std::size_t,Min>,
std::integral_constant<std::size_t,Min-1>
>{};
template<std::size_t Min, template<std::size_t N>class target>
struct maximize<Min, 0, target>:
std::integral_constant<std::size_t,Min-1>
{};
template<class T>
struct construct_searcher {
template<std::size_t N>
using result = ::can_construct_with_N<T, N>;
};
template<class T, std::size_t Cap=4>
using construct_arity = details::maximize< 0, Cap, details::construct_searcher<T>::template result >;
template<typename T>
constexpr auto tie_as_tuple_impl(std::integral_constant<size_t, 1>, T&& t){
auto&& [a] = t;
return std::tie(a);
}
template<typename T>
constexpr auto tie_as_tuple_impl(std::integral_constant<size_t, 2>, T&& t){
auto&& [a,b] = t;
return std::tie(a,b);
}
template<typename T>
constexpr auto tie_as_tuple_impl(std::integral_constant<size_t, 3>, T&& t){
auto&& [a,b,c] = t;
return std::tie(a,b,c);
}
template<size_t S, typename T>
constexpr auto tie_as_tuple(T&& t){
return tie_as_tuple_impl(std::integral_constant<size_t, S>{}, std::forward<T>(t));
}
}
template<typename T>
constexpr auto tie_as_tuple(T&& t){
constexpr size_t S = details::construct_arity<std::decay_t<T>>::value;
return details::tie_as_tuple<S>(std::forward<T>(t));
}
现在,您可以使用tie_as_tuple
以您要求的方式创建一个元组,其中包含您已经定义的所有运算符。
请注意,我必须准备几个tie_as_tuple_impl
的重载,一个结构中每个元素的数量,但是对于struct元素的数量线性扩展。
答案 1 :(得分:2)
我可以用一些通用的方式做到这一点,没有用任何反射巫术装饰我的结构定义 - 并且没有拼写出所有那些操作符定义吗?
不,没有办法用当前的c ++标准以通用的方式实现这一点。
我甚至不知道你对“reflection voodo”的意思,因为标准不支持类型反射(还)。
即使将来如此,我也怀疑像列表中的字典顺序这样的操作将首先出现。
或者是否能够做到太多依赖“语言反思”的期望?
可能是的。您可以尝试使用像c#这样的语言,但它有反射,但提供通用运算符实现仍然很棘手。
答案 2 :(得分:1)
目前没有类似
的快捷方式auto operator < (const foo &a, const foo &b) {
return std::tie(a.x, a.y) < std::tie(b.x, b.y);
}
在标准C ++中(以及在Boost afaics中)。
由于这确实是不必要且容易出错的类型,Defaulted comparison operators已被提出,但尚未添加到标准C ++中(截至目前的C ++ 17草案)。
答案 3 :(得分:0)