多种遗产声明的可变参数模板-“ ...通过3个模板参数声明...”

时间:2020-05-03 07:39:20

标签: c++ variadic-templates static-methods constexpr tag-dispatching

我正在尝试为自己的AVR编程实现自己的std::is_base_of(avr-gcc尚不支持<type_traits>。我从{{ 3}},它可以用于单个类型检查,但是,我要实现的是对一个基类的多个类型继承的静态执行的有效性检查。 / p>

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

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


选项标签

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

单个Heritage Validator结构

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)!

是否可以使用其他参数重新定义结构模板,例如上面的尝试多次检查中的?

2 个答案:

答案 0 :(得分:1)

在c ++ 17中,您可以在String运算符上使用fold-expression来实现这一目标

&&

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

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
};

答案 1 :(得分: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...>;