多个遗产断言的可变模板----".用3个模板参数重新声明."

问题描述 投票:0回答:2

我正在努力实现自己的 std::is_base_of 用于我的AVR编程(avr-gcc还不支持 <type_traits>. 我的灵感来自于 可能的实施 关于 cppreference页面它的工作原理是 单一 类型检查。然而,我想实现的是一个静态执行的有效性检查的 多重 类型的一个基类的遗产。

为了简单起见,我使用 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不支持全c++14中的for-loops)。constexpr 函数),我希望能够使用参数解包,并检查所有的选项标签是否有我的基础标签的遗产(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)!

有没有什么方法可以用另一个数量的参数来重新定义一个结构模板呢?多次检查的尝试 以上?

c++ variadic-templates static-methods constexpr tag-dispatching
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...>;

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;
};
© www.soinside.com 2019 - 2024. All rights reserved.