Выполнение static_assert, что тип шаблона является другим шаблоном - программирование
Подтвердить что ты не робот

Выполнение static_assert, что тип шаблона является другим шаблоном

Как мне static_assert нравится это? Может быть, Boost поддерживает его, если не С++ или новые функции в С++ 11?

template<T>
struct foo {};

template<FooType>
struct bar {
  static_assert(FooType is indeed foo<T> for some T,"failure"); //how?
};
4b9b3361

Ответ 1

Вы могли бы что-то сделать в этом направлении. Учитывая черту, которая может проверить, является ли класс экземпляром шаблона класса:

#include <type_traits>

template<typename T, template<typename> class TT>
struct is_instantiation_of : std::false_type { };

template<typename T, template<typename> class TT>
struct is_instantiation_of<TT<T>, TT> : std::true_type { };

Используйте его в своей программе следующим образом:

template<typename T>
struct foo {};

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<FooType, foo>::value, "failure");
};

int main()
{
    bar<int> b; // ERROR!
    bar<foo<int>> b; // OK!
}

Если вы хотите, вы можете обобщить это, чтобы определить, является ли класс экземпляром шаблона с любым количеством параметров (типа), например:

#include <type_traits>

template<template<typename...> class TT, typename T>
struct is_instantiation_of : std::false_type { };

template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : std::true_type { };

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<foo, FooType>::value, "failure");
};

Затем вы будете использовать его таким образом в своей программе:

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<foo, FooType>::value, "failure");
};

int main()
{
    bar<int> b; // ERROR!
    bar<foo<int>> b; // OK!
}

Вот живой пример.

Ответ 2

Как писал кто-то другой,

template<typename T, template<typename...> class TT>
struct is_specialization_of : std::false_type { };

template<template<typename...> class TT, typename... Ts>
struct is_specialization_of<TT<Ts...>, TT> : std::true_type { };

Однако будьте осторожны, что это работает только для классов шаблонов, параметры шаблонов которых являются все typenames! Представлено

typedef std::array<int, 42> MyArray;
static_assert(is_specialization_of<MyArray, std::array>::value, "");

он просто не скомпилируется вообще.

Я считаю, что С++ 11/С++ 14/С++ 17 не имеет способа справиться с этим ограничением.

Ответ 3

Некоторые небольшие улучшения по сравнению с другими ответами:

  • имя действительно имеет смысл в отношении порядка параметров
  • обрабатывает const, volatile и правильные ссылочные типы через std:: decay
  • реализует переменную типа _v constexpr С++ 14
  • принимает произвольное количество типов для тестирования (тесты для ALL)

Я намеренно не помещал std:: decay_t в is_template_for_v, потому что черта типа должна работать одинаково независимо от того, вызвана ли она суффиксом _v или нет.

Для этого требуется С++ 17 для std::conjunction, но вы можете либо удалить вариационную функцию, либо реализовать свой собственный conjunction с помощью С++ 11/14.

template<template<class...> class tmpl, typename T>
struct _is_template_for : public std::false_type {};

template<template<class...> class tmpl, class... Args>
struct _is_template_for<tmpl, tmpl<Args...>> : public std::true_type {};

template<template<class...> class tmpl, typename... Ts>
using is_template_for = std::conjunction<_is_template_for<tmpl, std::decay_t<Ts>>...>;

template<template<class...> class tmpl, typename... Ts>
constexpr bool is_template_for_v = is_template_for<tmpl, Ts...>::value;

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

static_assert(is_template_for_v<std::vector, std::vector<int>>); // doesn't fire