std::is_complete

croessmah
croessmah

Бывает необходимо проверить завершенность типа, переданного в шаблон.

 

struct A;//incomplete type

struct B {}//complete type

//...

template<typename T>
void foo()
{
   static_assert (std::is_complete<T>::value, "T must be complete");
   //...
}


template<typename T>
void bar()
{
   if constexpr (std::is_complete_v<T>) {
      //...
   } else {
      //...
   }
   //...
}
10
рейтинг
5 комментариев
yndx-antoshkka
На подобную тему был комментарий от России к C++17. В комментарии было требование, чтобы все type_triat проверяли тип на "завершённость" (если обратное не оговорено заранее:

"Failed prerequirement for the type trait must result in ill-formed program. Otherwise hard detectable errors will happen"

Это будет исправлено в ближайшее время, и почти все type_trait будут внутри иметь static_assert(complete). Можно будет ассертить на полноту например вот так:

template<class T>
constexpr void assert_complete() {
(void)std::is_pod_v<T>;
}


Сделать именно type_trait std::is_complete_v<T> a не assert - невозможно, т.к. такой type_trait будет нарушать ODR и будет "запоминать" первый результат применения для типа T и всегда выдавать его.
yndx-antoshkka
ru.night.beast
не знаю, насколько соответствует стандарту, но на gcc работает.
только вот строить логику на завершенности типа имхо не правильно.

typedef int yes_type;
typedef char no_type;

template <typename T>
constexpr std::enable_if_t<sizeof(T), yes_type> is_complete_impl(T*);

constexpr no_type is_complete_impl(...);

template <int unique, typename T>
constexpr inline bool is_complete () { return sizeof(yes_type) == sizeof(is_complete_impl((T*)0)); }

struct Test;
constexpr bool e1 = is_complete<__LINE__,Test>();

struct Test {};
constexpr bool e2 = is_complete<__LINE__,Test>();

int main()
{
static_assert(e1 == false, "");
static_assert(e2 == true, "");
}
ru.night.beast
yndx-antoshkka
ru.night.beast,

В треде boost.2283326.n4.nabble.com/type-traits-is-complete-lt-T-gt-possible-realization-tc4638134.html John Maddock приводит пример, где подобный трейт приведёт к ODR:

// Begin Translation Unit A
struct foo;

template< class T >
struct your_code
{
// Do something valid when the type is incomplete
};
// End Tranlation Unit A

// Begin Translation Unit B
struct foo {};

template< class T >
struct your_code
{
// Do something valid when the type is complete
};
// End Tranlation Unit B

//////////


Так что реализация, которая не добавляет проблем, это только assert_complete(). Добавление именно трейта будет очень неявно и трудноуловимо ломать код.
yndx-antoshkka
ru.night.beast
yndx-antoshkka, кстати насчет трудноуловимости. какие-нибудь варнинги при линковке на нарушение ОДР не планируют добавить?
ru.night.beast
croessmah
yndx-antoshkka, в принципе, мне и одних assert'ов хватит.
croessmah
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).