【问题标题】:Detecting if two classes are siblings检测两个类是否是兄弟姐妹
【发布时间】: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 甚至不再被使用了!它看起来是一个需要完成的重大项目,我将尝试自己完成。

【问题讨论】:

标签: c++ templates c++11 variadic


【解决方案1】:

“是否有不依赖于定义parents 成员类型的类的解决方案” - 在纯 C++ 中通常没有比这更方便的了。 (其他选项相当于记录您的parents 成员较少直接添加的相同类型的信息 - 例如,在类型特征中;如果您想查看人们已经破解了什么,请搜索“C++ 内省库”或“C++ 反射库”)。

有些工具可以输出抽象语法树表示(例如 clang/llvm),然后可以由创建 C++ 代码的工具读取/处理,但相对而言很少值得将它们引入您的构建过程......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 2022-05-30
    • 2022-05-30
    相关资源
    最近更新 更多