类地图容器和类向量容器之间的歧义模板专业化 [英] Disambiguate template specialization between map-like and vector-like containers
问题描述
template< class> struct打印机;
//我希望它与std :: vector(和类似的线性容器)匹配
template< template< class,class ...> T类,TV类,类... TS>
struct Printer< T< TV,TS ...> {...};
//我希望它与std :: map(和类似的类似地图的容器)匹配
template< template< template,class,class,class ...> TM类,TK类,TV类,类型名称... TS>
struct Printer< TK,TV,TS ...> {...}
int main()
{
//两者都与第二个专业化匹配,后者仅用于
// std ::地图(以及类似的类似地图的容器)
Printer< std :: vector< int>> :: something();
Printer< std :: map< int,float>> ::: something();
}
从示例中可以看到, std: :vector
和 std :: map
都与第二个专业化匹配。我认为这是因为 std :: vector
的分配器参数与 TV
匹配,后者旨在用于 std :: map
的值。
如何将 std :: vector
(和其他线性容器)与
<,第一个专业化标签和
std :: map
(以及其他键值容器)? div class = h2_lin>解决方案模式匹配方法的问题在于,只有为每个编写了专门化的容器的容器,它才有效。
相反,您可以依靠其他属性:
- 容器必须可以通过
begin(c)
和end(c)
表达式 $ b进行迭代$ b - 最重要的是,关联容器将具有
:: key_type
嵌套类型,如§23.2.4 [associative .rqmts] 。
因此,我们可以基于标签分发 >:
内联constexpr auto is_container_impl(...)-> std :: false_type {
return std :: false_type {};
}
模板< typename C>
constexpr auto is_container_impl(C const * c)->
decltype(begin(* c),end(* c),std :: true_type {})
{
return std :: true_type {};
}
模板< typename C>
constexpr auto is_container(C const& c)-> decltype(is_container_impl(& c)){
return is_container_impl(& c);
}
内联constexpr自动is_associative_container_impl(...)
-> std :: false_type
{return std :: false_type {}; }
模板< typename C,typename = typename C :: key_type>
constexpr auto is_associative_container_impl(C const *)-> std :: true_type {
return std :: true_type {};
}
模板< typename C>
constexpr auto is_associative_container(C const& c)
-> decltype(is_associative_container_impl(& c))
{
return is_associative_container_impl(& c);
}
现在您可以编写简单代码:
模板< typename C>
void print_container(C const& c,std :: false_type / * is_associative * /){
}
模板< typename C>
void print_container(C const& c,std :: true_type / * is_associative * /){
}
模板< typename C>
void print_container(C const& c){
return print_container(C,is_assocative_container(c));
}
现在,这可能并不是您想要的,因为在此要求下集合
是一个关联容器,但它的值不是对
,因此无法打印键:值
。您必须根据需要调整标签分配。
template<class> struct Printer;
// I want this to match std::vector (and similar linear containers)
template<template<class, class...> class T, class TV, class... TS>
struct Printer<T<TV, TS...>> { ... };
// I want this to match std::map (and similar map-like containers)
template<template<class, class, class...> class TM, class TK, class TV, typename... TS>
struct Printer<TM<TK, TV, TS...>> { ... }
int main()
{
// Both of these match the second specialization, which is only intended
// for std::map (and similar map-like containers)
Printer<std::vector<int>>::something();
Printer<std::map<int, float>>::something();
}
As you can see from the example, std::vector
and std::map
both match the second specialization. I think it's because std::vector
's allocator parameter gets matched to TV
, which is intended for std::map
's value.
How can I match std::vector
(and other linear containers) with the first specialization and std::map
(and other key-value containers) with the second one?
The problem with the pattern-matching approach is that it will only ever work if for every single container you write a specialization. This is tedious work.
Instead you can rely on other properties:
- a container will necessarily be iterable over via
begin(c)
andend(c)
expressions - on top of this, an associative container will have a
::key_type
nested type, among others, as expressed in § 23.2.4 [associative.rqmts].
Therefore, we can whip up a classifier, based on tag dispatching:
inline constexpr auto is_container_impl(...) -> std::false_type {
return std::false_type{};
}
template <typename C>
constexpr auto is_container_impl(C const* c) ->
decltype(begin(*c), end(*c), std::true_type{})
{
return std::true_type{};
}
template <typename C>
constexpr auto is_container(C const& c) -> decltype(is_container_impl(&c)) {
return is_container_impl(&c);
}
inline constexpr auto is_associative_container_impl(...)
-> std::false_type
{ return std::false_type{}; }
template <typename C, typename = typename C::key_type>
constexpr auto is_associative_container_impl(C const*) -> std::true_type {
return std::true_type{};
}
template <typename C>
constexpr auto is_associative_container(C const& c)
-> decltype(is_associative_container_impl(&c))
{
return is_associative_container_impl(&c);
}
And now you can write "simple" code:
template <typename C>
void print_container(C const& c, std::false_type/*is_associative*/) {
}
template <typename C>
void print_container(C const& c, std::true_type/*is_associative*/) {
}
template <typename C>
void print_container(C const& c) {
return print_container(C, is_assocative_container(c));
}
Now, this might not be exactly what you wish for, because under this requirements a set
is an associative container, but its value is not a pair
, so you cannot print key: value
. You have to adapt the tag-dispatching to your needs.
这篇关于类地图容器和类向量容器之间的歧义模板专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!