std::map 的所有迭代器的模板特化
template specialization for all iterators of std::map
我有特质class,说:
template <class T>
struct KeyValueTraits
{
typedef typename T::key_t key_t;
typedef typename T::value_t value_t;
}
现在我想为 std::map
的所有迭代器声明此特征的特化
template < typename... Args >
struct KeyValueTraits<typename std::map<Args...>::iterator >
{
typedef std::map<Args...> target_t;
typedef typename target_t::key_type key_t;
typedef typename target_t::mapped_type value_t;
};
编译器报错:
error C2764: 'Args': template parameter not used or deducible in partial specialization
那么如何声明所有可能的特征类型std::map<...>::iterator
?
你使用可变模板参数,所以我想你可以接受 C++11 解决方案。
我提出以下(不是很好)基于模板专业化的解决方案。
请注意 std::map<>
中键的类型不是 key_t
而是 key_type
并且值的类型不是 value_t
但 mapped_type
.
#include <map>
template <typename X>
struct with_kt
{
template <typename Y = X>
static constexpr bool getValue (int, typename Y::key_type * = nullptr)
{ return true; }
static constexpr bool getValue (long)
{ return false; }
static constexpr bool value { getValue(0) };
};
template <typename T, bool = with_kt<T>::value>
struct KeyValueTraits;
template <typename T>
struct KeyValueTraits<T, true>
{
using key_t = typename T::key_type;
using value_t = typename T::mapped_type;
};
template <typename T>
struct KeyValueTraits<T, false>
{
using pair_t = decltype(* std::declval<T>());
using key_t = typename std::remove_const<
decltype(std::declval<pair_t>().first)>::type;
using value_t = decltype(std::declval<pair_t>().second);
};
using mil = std::map<int,long>;
int main()
{
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::iterator>::key_t
>::value, "!");
static_assert(std::is_same<KeyValueTraits<mil>::value_t,
KeyValueTraits<mil::iterator>::value_t
>::value, "!!");
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::const_iterator>::key_t
>::value, "!!!");
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::reverse_iterator>::key_t
>::value, "!!!!");
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::const_reverse_iterator>::key_t
>::value, "!!!!!");
}
这是一种可能的解决方案(它更改了 KeyValueTraits 模板签名,因为否则似乎不可能)。
template <class T, class = void>
struct KeyValueTraits
{
typedef typename T::key_t key_t;
typedef typename T::value_t value_t;
};
template <class MapIter>
struct KeyValueTraits<MapIter,
typename std::enable_if<
sizeof(std::declval<MapIter>()->first) &&
sizeof(std::declval<MapIter>()->second)
>::type>
{
typedef decltype(std::declval<MapIter>()->first) key_t;
typedef decltype(std::declval<MapIter>()->second) value_t;
};
我有特质class,说:
template <class T>
struct KeyValueTraits
{
typedef typename T::key_t key_t;
typedef typename T::value_t value_t;
}
现在我想为 std::map
template < typename... Args >
struct KeyValueTraits<typename std::map<Args...>::iterator >
{
typedef std::map<Args...> target_t;
typedef typename target_t::key_type key_t;
typedef typename target_t::mapped_type value_t;
};
编译器报错:
error C2764: 'Args': template parameter not used or deducible in partial specialization
那么如何声明所有可能的特征类型std::map<...>::iterator
?
你使用可变模板参数,所以我想你可以接受 C++11 解决方案。
我提出以下(不是很好)基于模板专业化的解决方案。
请注意 std::map<>
中键的类型不是 key_t
而是 key_type
并且值的类型不是 value_t
但 mapped_type
.
#include <map>
template <typename X>
struct with_kt
{
template <typename Y = X>
static constexpr bool getValue (int, typename Y::key_type * = nullptr)
{ return true; }
static constexpr bool getValue (long)
{ return false; }
static constexpr bool value { getValue(0) };
};
template <typename T, bool = with_kt<T>::value>
struct KeyValueTraits;
template <typename T>
struct KeyValueTraits<T, true>
{
using key_t = typename T::key_type;
using value_t = typename T::mapped_type;
};
template <typename T>
struct KeyValueTraits<T, false>
{
using pair_t = decltype(* std::declval<T>());
using key_t = typename std::remove_const<
decltype(std::declval<pair_t>().first)>::type;
using value_t = decltype(std::declval<pair_t>().second);
};
using mil = std::map<int,long>;
int main()
{
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::iterator>::key_t
>::value, "!");
static_assert(std::is_same<KeyValueTraits<mil>::value_t,
KeyValueTraits<mil::iterator>::value_t
>::value, "!!");
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::const_iterator>::key_t
>::value, "!!!");
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::reverse_iterator>::key_t
>::value, "!!!!");
static_assert(std::is_same<KeyValueTraits<mil>::key_t,
KeyValueTraits<mil::const_reverse_iterator>::key_t
>::value, "!!!!!");
}
这是一种可能的解决方案(它更改了 KeyValueTraits 模板签名,因为否则似乎不可能)。
template <class T, class = void>
struct KeyValueTraits
{
typedef typename T::key_t key_t;
typedef typename T::value_t value_t;
};
template <class MapIter>
struct KeyValueTraits<MapIter,
typename std::enable_if<
sizeof(std::declval<MapIter>()->first) &&
sizeof(std::declval<MapIter>()->second)
>::type>
{
typedef decltype(std::declval<MapIter>()->first) key_t;
typedef decltype(std::declval<MapIter>()->second) value_t;
};