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)
. Ако изразът в trailing-return-type не е валиден, тогава това конкретно претоварване на 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