0

我正在尝试std::is_base_of为我的 AVR 编程实现我自己的(avr-gcc 尚不支持。我从 cppreference 页面可能的实现<type_traits>中获得灵感,它适用于单一类型检查。但是,我想要实现的是静态对一个基类的多种类型的继承执行有效性检查。

为简单起见,我 std::is_base_of 用于下面的实际检查,但是我的实际解决方案与上面链接的 cppreference 页面中的内容接近。

我将使用它进行标签调度,更具体地说是允许任何顺序的选项标签。


选项标签

struct tOption {};
struct tThis : public tOption {};
struct tThat : public tOption {};
struct tElse {}; // Wrongly defined option tag!

单一遗产验证器结构

template<typename TBase, typename TCandidate>
struct isBaseOf {
    isBaseOf() = delete;
    static const bool value = std::is_base_of<TBase, TCandidate>::value;
};

static_assert(isBaseOf<tOption, tThat>::value, "Invalid option tag!"); // OK!
static_assert(isBaseOf<tOption, tElse>::value, "Invalid option tag!"); // ERROR! Invalid option tag!

尝试多次检查(上述isBaseOf声明的补充)

template<typename TBase, typename TCandidate, typename... TRest>
struct isBaseOf {
    isBaseOf() = delete;
    static const bool value = isBaseOf<TBase, TRest...>::value && 
                              std::is_base_of<TBase, TCandidate>::value;
};

这不起作用。据我所知,我无法使用不同数量的类型重新声明模板。但是,我在最后一个模板构造中至少需要两种类型。我尝试将 TBase 作为唯一参数并将值设置为 true,但同样的问题仍然存在:错误:使用 3 个模板参数重新声明


用法

如前所述,这仅限于单次检查。由于我的类(此处未显示)对任意数量的选项标签使用可变参数模板(并且 avr-gcc 不支持constexpr函数中带有 for 循环的完整 c++14),我希望能够使用参数解包并仍然检查所有选项标签都继承了我的基本标签 ( tOption)。

template<typename... TOptions>
class tMyClass {
    static_assert(isBaseOf<tOption, TOptions...>::value, "Invalid option tag(s)!"); // <--- THIS
    // ...
};

使用函数 - 丑陋和不需要的

我让它使用一个函数而不是另一个结构来工作,但我认为这很令人困惑。我宁愿有一种方法来解决整个递归(静态)堆栈中的问题。此外,这迫使我构建每个标签,这不是很整洁的 IMO。

template<typename TBase, typename TCandidate>
constexpr bool isBaseOf2(const TBase&, const TCandidate&) {
    return std::is_base_of<TBase, TCandidate>::value;
}

template<typename TBase, typename TCandidate, typename... TRest>
constexpr bool isBaseOf2(const TBase& base, const TCandidate&, const TRest&... rest) {
    return isBaseOf2(base, rest...) && std::is_base_of<TBase, TCandidate>::value;
}

static_assert(isBaseOf2(tOption{}, tThis{}, tThat{}), "Invalid option tag(s)!"); // OK!
static_assert(isBaseOf2(tOption{}, tThis{}, tElse{}), "Invalid option tag(s)!"); // ERROR! Invalid option tag(s)!

有没有办法用其他数量的参数重新定义结构模板,例如上面的多次检查尝试

4

2 回答 2

1

问题

template<typename TBase, typename TCandidate, typename... TRest>
struct isBaseOf {
    isBaseOf() = delete;
    static const bool value = isBaseOf<TBase, TRest...>::value && 
                              std::is_base_of<TBase, TCandidate>::value;
};

就这样结束了吗,你完成了:

static const bool value = isBaseOf<TBase, /*Empty Pack*/>::value && 
                          std::is_base_of<TBase, TCandidate>::value;

isBaseOf<TBase, TRest...>对空包无效。

您必须添加专业化来处理这种情况:

template<typename TBase, typename TCandidate>
struct isBaseOf<TBase, TCandidate> {
    isBaseOf() = delete;
    static const bool value = std::is_base_of<TBase, TCandidate>::value;
};

没有递归的替代方案:

template <bool... Bs> struct Bools{};
template <bool... Bs> using All = std::is_same<Bools<true, Bs...>, Bools<Bs..., true>>;

template<typename TBase, typename... TCandidates>
using isBaseOf = All<std::is_base_of<TBase, TCandidates>::value...>;
于 2020-05-03T12:00:53.710 回答
1

在 c++17 中,您可以在运算符上使用折叠表达式&&来实现此目的

template<typename Base, typename ...Candidates>
struct is_base_of_multiple {
    static constexpr bool value = (std::is_base_of_v<Base, Candidates> && ...); // change std::is_base_of_v to your own implementation
};

如果您不能使用 c++17,但可以使用 c++11,这是另一种仅使用可变参数模板的方法

template <typename Base, typename First, typename ...Rest>
struct is_base_of_multiple {
    static constexpr bool value = std::is_base_of<Base, First>::value && is_base_of_multiple<Base, Rest...>::value;
};

template <typename Base, typename Candidate>
struct is_base_of_multiple<Base, Candidate> {
    static constexpr bool value = std::is_base_of<Base, Candidate>::value;
};
于 2020-05-03T07:56:26.917 回答