我正在尝试为自己的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)!
是否可以使用其他参数重新定义结构模板,例如上面的尝试多次检查中的?
答案 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...>;