Использование SFINAE для проверки того, завершен ли тип или нет
Можно ли проверить с помощью SFINAE, если тип полностью определен?
Например
template <class T> struct hash;
template <> struct hash<int> {};
// is_defined_hash_type definition...
enum Enum { A, B, C, D };
static_assert ( is_defined_hash_type<int> ::value, "hash<int> should be defined");
static_assert (! is_defined_hash_type<Enum>::value, "hash<Enum> should not be defined");
Решение не должно изменять хэш-структуру.
Ответы
Ответ 1
Вы можете сделать is_complete
типа is_complete
, используя тот факт, что он плохо сформирован для оценки sizeof(T)
для неполного типа T
:
template <typename T>
struct is_complete_helper {
template <typename U>
static auto test(U*) -> std::integral_constant<bool, sizeof(U) == sizeof(U)>;
static auto test(...) -> std::false_type;
using type = decltype(test((T*)0));
};
template <typename T>
struct is_complete : is_complete_helper<T>::type {};
и использовать его для проверки is_defined_hash_type<T>
путем определения того, завершено ли hash<T>
. (Live at Coliru)
Как говорит Даниил в своем ответе, полезность такой вещи ограничена. Этот признак фактически не проверяет, завершен ли тип в точке кода, где вы запрашиваете, он проверяет, был ли тип завершен в точке в программе, где этот признак был впервые создан для заданного типа.
Ответ 2
Это невозможно. Причина в том, что вам нужно будет определить is_defined_hash_type<T>
но может быть только одно определение. Но если вы позже определите T
, определение is_defined_hash_type<T>
даст другой результат, следовательно, другое определение, и это не разрешено. Это нарушение ODR (одно правило определения).
Ответ 3
Лучшее, что я придумал до сих пор, - это следующее, которое требует по крайней мере typedef
с общим именем во всей специализации hash
:
template <class T> struct hash;
template <> struct hash<int> {
typedef int value_type;
};
template<class T>
constexpr bool is_defined_hash_type(typename hash<T>::value_type) {
return true;
}
template<class T>
constexpr bool is_defined_hash_type(T) {
return false;
}
int main()
{
static_assert ( is_defined_hash_type< int >(0), "hash<int> should be defined");
static_assert (! is_defined_hash_type< double>(0), "hash<Enum> should not be defined");
return 0;
}
Синтаксис довольно уродливый из-за добавленного параметра (необходимого для запуска SFINAE). Если вы думаете, что это может быть дорога, я постараюсь почистить ее дальше.
Отказ от ответственности: я отнюдь не эксперт С++ 11, поэтому я, возможно, пропустил некоторые моменты, используя новые функции. В этом случае огонь по желанию, и я постараюсь исправить ответ.