【发布时间】:2015-10-05 23:57:21
【问题描述】:
有人可以改进我在下面对are_siblings 的糟糕实现吗?它只是猜测所有可能的父母,然后根据这些父母候选人来决定这两个班级是否是兄弟姐妹。
#include <type_traits>
template <bool...> struct Or;
template <bool First, bool... Rest>
struct Or<First, Rest...> : std::conditional<First,
std::true_type, Or<Rest...>>::type {};
template <>
struct Or<> : std::false_type {};
template <typename T, typename U, typename... Parents>
struct are_siblings :
Or<(std::is_base_of<Parents, T>::value && std::is_base_of<Parents, U>::value
&& !std::is_base_of<T,U>::value && !std::is_base_of<U,T>::value)...> {};
// Test
#include <iostream>
struct A {};
struct B : A {};
struct C : A {};
struct D : A, C {};
struct E : B, C {};
int main() {
std::cout << std::boolalpha << are_siblings<D,E, A,B,C>::value << '\n'; // true
std::cout << are_siblings<C,D, A,B,E>::value << '\n'; // false
std::cout << are_siblings<B,E, A,B,E>::value << '\n'; // false
}
如果有办法在编译时获取一个类的所有父类,那么我认为这将解决问题。
更新:
下面无需猜测父候选者,但理想情况下是否存在不依赖于定义parents 成员类型的类的解决方案?
#include <type_traits>
#include <tuple>
template <bool...> struct Or;
template <bool First, bool... Rest>
struct Or<First, Rest...> : std::conditional<First,
std::true_type, Or<Rest...>>::type {};
template <>
struct Or<> : std::false_type {};
template <typename T, typename U, typename Parents> struct are_siblings_helper;
template <typename T, typename U, template <typename...> class P, typename... Parents>
struct are_siblings_helper<T, U, P<Parents...>> :
Or<(std::is_base_of<Parents, T>::value && std::is_base_of<Parents, U>::value
&& !std::is_base_of<T,U>::value && !std::is_base_of<U,T>::value)...> {};
template <typename, typename> struct merge;
template <template <typename...> class P, typename... Ts, typename... Us>
struct merge<P<Ts...>, P<Us...>> {
using type = P<Ts..., Us...>;
};
template <typename T, typename U>
struct are_siblings : are_siblings_helper<T,U,
typename merge<typename T::parents, typename U::parents>::type> {};
// Test
#include <iostream>
struct A {};
struct B : virtual A {
using parents = std::tuple<A>;
};
struct C : virtual A {
using parents = std::tuple<A>;
};
struct D : virtual A, C {
using parents = std::tuple<A,C>;
};
struct E : virtual B, virtual C {
using parents = std::tuple<B,C>;
};
int main() {
std::cout << std::boolalpha << are_siblings<D,E>::value << '\n'; // true
std::cout << are_siblings<C,D>::value << '\n'; // false
std::cout << are_siblings<B,E>::value << '\n'; // false
}
进一步更新:
如果您有兴趣,可以使用更新后的代码查看该项目的发展方向:
http://ideone.com/UQJ3WZ
std::is_base_of 甚至不再被使用了!它看起来是一个需要完成的重大项目,我将尝试自己完成。
【问题讨论】:
-
我很好奇你为什么要建造这个。你想解决什么问题?
-
首先,定义“兄弟姐妹”。
-
类至少有一个共同的父级,但一个不是另一个的后代?
-
@Dai 出于同样的原因,有人提出了
std::is_base_of。它可能很有用。 -
is_base_of 如果基础位于派生层次结构中的任何位置,则为真。所以 is_base_of 为真,因为 B 是 E 的基础,所以任何作为 B 基础的类也是 E 的基础。(标准中的一个例子说明了这一点。)
标签: c++ templates c++11 variadic