Шаблоны Variadi c для нескольких утверждений о наследовании - "... объявлено с 3 параметрами шаблона ..." - PullRequest
0 голосов
/ 03 мая 2020

Я пытаюсь реализовать свой собственный std::is_base_of для моего программирования AVR (avr-g cc пока не поддерживает <type_traits>. Я вдохновился возможной реализацией на cppreference page , она работала для одиночной проверки типа. Однако я хочу добиться статически выполняемых проверок достоверности множественных типов наследования одного базового класса.

Для простоты я использую 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 параметрами шаблона


Использование

Как уже упоминалось, это ограничивается одной проверкой. Поскольку мой класс (здесь не показан) использует шаблоны variadi c для любого количества тегов параметров (а avr-g cc не поддерживает полноценный c ++ 14 с циклами for в функциях constexpr), я хочу быть в состоянии использовать распаковку параметров и все еще проверять, что все теги параметров имеют наследие моего базового тега (tOption).

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

Использование функций - Уродливые и нежелательные

Я заставил его работать, используя функцию вместо другой структуры, но я думаю, что это сбивает с толку. Я предпочел бы иметь один способ решения проблемы во всем рекурсивном (stati c) стеке. Кроме того, это заставляет меня создавать каждый тег, который не очень аккуратный 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 ]

1 голос
/ 03 мая 2020

Проблема с

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

Это конец, вы закончили sh с:

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 голос
/ 03 мая 2020

В 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, вот еще один способ сделать это с помощью просто variadi c templates

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;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...