Подтвердить что ты не робот

Как я могу сделать этот код вариационного шаблона короче, используя функции из С++ 14 и С++ 1z?

Это фрагмент кода, который я собираюсь использовать, чтобы проверить, уникальны ли типы вариационных шаблонов:

template <typename...>
struct is_one_of;

template <typename F>
struct is_one_of<F> {
    static constexpr bool value = false;
};

template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
    static constexpr bool value =
        std::is_same<F, S>::value || is_one_of<F, T...>::value;
};

template <typename...>
struct is_unique;

template <>
struct is_unique<> {
    static constexpr bool value = true;
};

template <typename F, typename... T>
struct is_unique<F, T...> {
    static constexpr bool value =
        is_unique<T...>::value && !is_one_of<F, T...>::value;
};

int main() {
    constexpr bool b = is_unique<bool, int, double>::value;
    constexpr bool c = is_unique<int, char, int>::value;
    static_assert(b == true && c == false, "!");
}

Есть ли способ сделать этот код короче и/или более кратким с использованием функций, представленных на С++ 14 и С++ 1z? Или есть лучший способ добиться такого же эффекта, используя новые функции?

В случае С++ 1z я имею в виду: функции, которые уже доступны в новейших версиях Clang и GCC.

4b9b3361

Ответ 1

#include <type_traits>

template <typename F, typename... Ts>
constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...);

template <typename...>
constexpr bool is_unique = true;

template <typename F, typename... Ts>
constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>;

DEMO

Ответ 2

Недавно мы добавили std:: disjunction в проект С++ 1z, который можно использовать для is_one_of (и он прекращает создание экземпляра, как только он находит матч, см. ссылку для получения дополнительной информации):

template <typename F, typename... T>
  using is_one_of = std::disjunction<is_same<F, T>...>;

Это уже реализовано в соединительной линии GCC. Для более старых версий GCC вы можете вместо этого использовать детальную реализацию __or_:

template <typename F, typename... T>
  using is_one_of = std::__or_<is_same<F, T>...>;

Или реализуйте disjunction вручную с использованием средств С++ 11, как показано в конце предложения, связанного выше.

Ответ 3

Я бы (сейчас) предложил использовать семейство STL-функций std::conj/disj/nega:

#include <type_traits>

template <typename H, typename... T>
struct is_one_of : std::disjunction<std::is_same<H, T>...> {};

template <typename H, typename... T>
struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {};

template <typename H>
struct is_unique<H> : std::true_type {};

int main()
{
    static_assert(is_one_of<int, char, double, int, bool>::value);
    static_assert(is_unique<int, char, double, bool>::value);
    static_assert(!is_unique<int, int, char, double, bool>::value);
}

Когда fold-expressions, которые были разработаны для этих случаев, выпущены на язык, это станет тривиальным:

namespace stx = std::experimental;

template <typename H, typename... T>
struct is_one_of {
    static constexpr bool value = (stx::is_same_v<H, T> || ...);
};

template <typename H, typename... T>
struct is_unique {
    static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value);
};

template <typename H>
struct is_unique<H> : std::true_type {};

Ответ 4

Я согласен с Брайаном Родригесом и Питером Сконтнинчи, насколько это касается части выражений. До тех пор, пока не будут сгибающие выражения, вы можете немного уменьшить существующий код, избавившись от неполных первичных шаблонов следующим образом:

template <typename...>
struct is_one_of {
    static constexpr bool value = false;
};

template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
    static constexpr bool value =
        std::is_same<F, S>::value || is_one_of<F, T...>::value;
};

template <typename...>
struct is_unique {
    static constexpr bool value = true;
};

template <typename F, typename... T>
struct is_unique<F, T...> {
    static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value;
};