2013-07-16 4 views
7

Я пытаюсь понять полезность static_assert, и я хочу знать, может ли он помочь мне в обеспечении исполнения дизайна, и если да, то каким образом.Enforce template type via static_assert

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

template <class T, size_t S = sizeof(T)> 
struct Helper; 

template <class T> 
struct Helper<T, sizeof(long)> 
{ 
    static T bar(); 
}; 

// ... other specializations ... 

template <class T> 
class Foo 
{ 
public: 

    T bar() 
    { 
     return Helper<T>::bar(); 
    } 
}; 

Foo поддерживается только если размер T поддерживается специализации Helper. Например, поддерживаются Foo<long> и Foo<unsigned long>. Однако предположим, что пользователь пытается построить Foo<bool>. Как правило, это порождает ошибки, поскольку специализация Помощник для bool не определен, что является предполагаемым поведением.

Есть ли способ использовать static_assert в этом дизайне, чтобы предоставить пользователю более полезные ошибки для этого интерфейса?

Кроме того, я хотел бы также ограничить пользователя использованием определенного типа, хотя размер может быть правильным. Например, Foo<float> не допускается. Прямо сейчас, единственный способ, которым я знаю, обеспечить это, - это смелый комментарий в документации. :)

+0

Подумайте, в общем, это только целые типы, которые поддерживаются? Нет 'char',' bool', 'float', et al? – Rapptz

+0

Поиск SO для ограничений типа шаблона или «понятий». Средство для этого было удалено с C++ 11 в последнюю минуту. Однако есть менее автоматические способы достижения подобных результатов. – luke

+0

@Rapptz, 'char',' int' и 'long', а также их' unsigned' версии должны поддерживаться. Код будет идентичным для 'int',' long' и 'unsigned long', если' sizeof (int) == sizeof (long) == sizeof (unsigned long) '. – Zeenobit

ответ

1

я понял, лучшее решение для этой проблемы путем объединения ответов и комментариев здесь.

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

template <class A, class B> 
struct CheckTypes 
{ 
    static const bool value = false; 
}; 

template <class A> 
struct CheckTypes<A, A> 
{ 
    static const bool value = true; 
}; 

Не уверен, что если такая структура уже существует в стандартной библиотеке.В любом случае, то в Foo, я могу проверить для типов и размеров с помощью:

static_assert((sizeof(T) == sizeof(long) || sizeof(T) == sizeof(int)) && !CheckTypes<T, float>::value, "Error!"); 
+1

он делает, std :: is_same –

+1

с использованием sizeof небезопасно. это просто размер. long и int могут быть одного размера, а случайная структура, которая содержит только int, также будет иметь тот же размер. –

13

Если он может работать только для специализации шаблона класса, то есть класс шаблона по умолчанию повысить статическую утверждать, что:

template <class T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(T) == -1,"You have to have a sepecialization for Helper!"); 
} 

Класс шаблона по умолчанию будет выбран только, если нет лучшая специализация, поэтому утверждение будет поднято.

Вы можете использовать ту же технику для запрещения типов, но вам понадобится другой параметр шаблона, который будет использоваться для проверки статического утверждения.

template <class T, class G = T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(G) == -1,"You have to have a sepecialization for Helper!"); 
} 

template <class G> 
struct Helper<float,G> 
{ 
    static_assert(sizeof(G) == -1,"You can't use float !"); 
} 

template <> 
struct Helper<int> 
{ 
//This is a good specialization 
}; 

Тогда вы можете попробовать его с этими переменными:

Helper<bool> a; //"You have to have a sepecialization for Helper!" 
Helper<float> b; //"You can't use float !" 
Helper<int> c; //compiles OK 
+1

Я считаю, что вы хотите 'static_assert (false, ...)', поэтому он всегда срабатывает. 'static_assert' печатает ошибку, если первый аргумент является ложным. –

+0

+1 для прагматичного ответа – sehe

+9

Это не сработает, как есть - вам нужно сделать зависимое утверждение (например, 'static_assert (sizeof (T) == 0, ...);'), в противном случае оно обрабатывается в точка декларации, а не инстанцирование. – Angew

3

http://en.cppreference.com/w/cpp/header/type_traits

std::is_base_of и std::is_convertible может помочь с вашим первым вопросом, и как для второго,

static_assert(!std::is_same<float,T>(),"type can't be float");

надеюсь, это поможет кому-то другому, кто наткнулся на этот вопрос, полагая, что OP, вероятно, нашел ответ за 4 года греха ce было задано :)

Смежные вопросы