Версия C ++ 11:
#include <type_traits>
template<class T>
struct satisfies_key_req{
struct nat{};
template<class K> static auto test(K* k) -> decltype(*k < *k);
template<class K> static nat test(...);
static bool const value = !std::is_same<decltype(test<T>(0)), nat>::value;
};
#include <iostream>
struct foo{};
int main(){
static bool const b = satisfies_key_req<int>::value;
std::cout << b << '\n';
static bool const b2 = satisfies_key_req<foo>::value;
std::cout << b2 << '\n';
}
Вывод:
1
0
Ключевым моментом, который я здесь использовал, является выражение SFINAE: auto test(K* k) -> decltype(*k < *k)
. Если выражение в завершающем-возвращаемом-типе недопустимо, то эта конкретная перегрузка test
удаляется из набора перегрузки. Другими словами, это SFINAE'd.
§14.8.2 [temp.deduct]
p6 В определенных точках процесса вывода аргументов шаблона необходимо выбрать тип функции, который использует параметры шаблона, и заменить эти параметры шаблона соответствующими аргументами шаблона. Это делается в начале шаблона. вывод аргументов, когда любые явно указанные аргументы шаблона подставляются в тип функции, и снова в конце вывода аргументов шаблона, когда заменяются любые аргументы шаблона, которые были выведены или получены из аргументов по умолчанию.
p7 Подстановка происходит во всех типах и выражениях, которые используются в типе функции и в объявлениях параметров шаблона. Выражения включают не только константные выражения, такие как те, которые появляются в границах массива или как аргументы шаблона, не являющиеся типами , но также и общие выражения (то есть непостоянные выражения) внутри sizeof
, decltype
и другие контексты, в которых разрешены непостоянные выражения.
p8 Если подстановка приводит к недопустимому типу или выражению, определение типа не выполняется. Недопустимый тип или выражение - это тот, который был бы неправильно сформирован, если бы он был записан с использованием подставленных аргументов. [...]
Вы можете использовать его в трех вариантах, чтобы ваш Foo
класс вызывал ошибку.
// static_assert, arguably the best choice
template< typename K >
class Foo
{
static_assert<satisfies_key_req<K>::value, "K does not satisfy key requirements");
// lots of other code here...
private:
std::map< K, size_t > m_map;
};
// new-style SFINAE'd, maybe not really clear
template<
typename K,
typename = typename std::enable_if<
satisfies_key_req<K>::value
>::type
>
class Foo
{
// lots of other code here...
private:
std::map< K, size_t > m_map;
};
// partial specialization, clarity similar to SFINAE approach
template<
typename K,
bool = satisfies_key_req<K>::value
>
class Foo
{
// lots of other code here...
private:
std::map< K, size_t > m_map;
};
template<typename K>
class Foo<K, false>;
person
Xeo
schedule
18.12.2011