用于多个遗产断言的可变参数模板 - "...redeclared with 3 template parameters..."



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

为了简单起见,我使用std::is_base_of进行下面的实际检查,但我的实际解决方案接近上面链接的cpprreference页面中的解决方案。

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


选项标签

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

是否有任何方法可以用其他数量的参数重新定义结构模板,例如上面的多次检查尝试

问题

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

在c++17中,可以在&&运算符上使用fold表达式来实现这个

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

最新更新