C++ 识别STL容器
通常,我想为不同的STL容器专门化一个函数。但是我不想一个接一个地专门化,因为它们中的一些共享大多数需要的接口,例如std::vector和std::deque 在我的用例中,主要有三类(向量类、集合类、地图类)。 例如,我想实现如下内容:C++ 识别STL容器,c++,templates,c++11,containers,C++,Templates,C++11,Containers,通常,我想为不同的STL容器专门化一个函数。但是我不想一个接一个地专门化,因为它们中的一些共享大多数需要的接口,例如std::vector和std::deque 在我的用例中,主要有三类(向量类、集合类、地图类)。 例如,我想实现如下内容: template <class T> struct A { template <class Y, class... Z> void func( Y y , Z... z ){ //hypothetica
template <class T>
struct A {
template <class Y, class... Z>
void func( Y y , Z... z ){
//hypothetical static_if
static_if ( T is similar to vector, deque, or boost::stable_vector etc which have push_back ) {
t.push_back(y);
}
else static_if ( T is similar to set, unordered_set or boost::flat_set etc which have emplace) {
t.emplace(y);
}
else static_if ( T is similar to map, unordered_map or boost::flat_map etc which has emplace) {
t.emplace(y, z...);
}
}
T t;
};
模板
结构A{
模板
无效函数(Y,Z…Z){
//假设静态假设
static_if(T类似于vector、deque或boost::stable_vector等,具有push_back){
t、 向后推(y);
}
else static_if(T类似于set、无序_set或boost::flat_set等,它们都有位置){
t、 炮位(y);
}
else static_if(T类似于map、无序_map或boost::flat_map等,具有安放位置){
t、 炮位(y,z…);
}
}
T;
};
我认为这似乎是不可能的,但我希望有一些黑客为这种情况。
如果可以扩展到列表类型(std::list,std::forward_list,…)或boost::heap或其他类型,这也很好。然而,实现这一目标似乎太难了 这不是不可能的,只是实现起来不方便,也不琐碎。实际上,需要一个
容器库
这可以通过使用来实现,以检测特定类型的容器
是否包含满足各种STL要求的必要功能
例如,is\u associative\u container
可以使用SFINAE检查container
类型是否具有键类型
和映射类型
typedef,以及值类型
的std::pair
,以及实现AssociateContainer
概念的对象的所有其他要求
无论如何,这确实需要作为一个成熟的库来实现。它的实现并不简单,如果您有一个简单的一次性需求,您可能应该寻找另一个解决方案。您最好在迭代器
级别进行抽象。这里是一个用于容器的粗糙类型特征库
template<typename Container>
struct container_traits;
template<bool b=true>
struct has_emplace_back { typedef std::integral_constant<bool, b> emplace_back; };
template<bool b=true>
struct has_emplace { typedef std::integral_constant<bool, b> emplace; };
template<typename T, typename A>
struct container_traits< std::vector<T,A> > : has_emplace_back<>, has_emplace<> {};
// etc
template<typename T, typename A>
struct container_traits< std::set<T,A> > : has_emplace_back<false>, has_emplace<> {};
// etc
template<typename T>
using HasEmplaceBack = typename container_traits<T>::has_emplace_back;
template<typename T>
using HasEmplace = typename container_traits<T>::has_emplace;
template<int> struct enum_enum { enum class type {}; };
template<int index> using UniqueEnum = typename enum_enum<index>::type;
template<bool b, int index=1>
using EnableIf = typename std::enable_if< UniqueEnum<index> >::type;
template<bool b, int index=1>
using DisableIf = EnableIf< b, -index >;
template<typename Container, typename... Args, EnableIf< HasEmplace<Container>::value && !HasEmplaceBack<Container>::value, 1 >... >
void emplace_in( Container&& c, Args&&... args ) {
std::forward<Container>(c).emplace( std::forward<Args>(args)... );
}
template<typename Container, typename... Args, EnableIf< HasEmplaceBack<Container>::value, 2 >... >
void emplace_in( Container&& c, Args&&... args ) {
std::forward<Container>(c).emplace_back( std::forward<Args>(args)... );
}
模板
结构容器特性;
模板
结构具有_emplace_back{typedef std::integral_constant emplace_back;};
模板
结构具有_位置{typedef std::integral_常量位置;};
模板
struct container_traits:has_emplace_back,has_emplace{};
//等
模板
struct container_traits:has_emplace_back,has_emplace{};
//等
模板
使用HasImplaceBack=typename容器\u traits::has\u emplace\u back;
模板
使用HasEmplace=typename容器\u traits::has\u emplace;
模板结构enum_enum{enum类类型{};};
使用uniquenum=typename enum_enum::type的模板;
模板
使用EnableIf=typename std::enable_if::type;
模板
使用DisableIf=EnableIf;
模板…>
在(容器和c、参数和…参数)中无效放置{
前进(c)炮位(前进(args)…);
}
模板…>
在(容器和c、参数和…参数)中无效放置{
标准:前进(c)。后置(标准:前进(args)…);
}
EnableIf…
技术在clang中不起作用,我没有编译它,因此可能需要一些调试来修复。我一周前尝试了sofisticated traits,但为了更好的可读性
请看下面的例子:不,对不起。不要这样做。Scott Meyers的有效STL中有一个完整的章节专门讨论这一点。下面是一段摘录,让您了解这一问题的严重性:
那么,假设您希望编写可用于
最常见的序列容器:vector、deque和list。清晰地
您必须编程到它们的能力的交叉点,并且
指不使用储备或容量(见第14项),因为:
不要提供它们。列表的存在还意味着您放弃了操作符[],您将自己限制在双向迭代器的功能范围内。这反过来意味着你必须远离那些
要求随机访问迭代器,包括排序、稳定排序、,
部分_排序和第n_元素(见第31项)
另一方面,您对支持向量的渴望排除了使用
向前推和向前推,vector和deque都打开了kibosh
拼接和排序的成员形式。结合上述限制,后一项禁令意味着不存在任何形式的限制
您可以在“通用序列容器”上调用的排序
这是显而易见的。如果您违反任何这些限制,您的
使用至少一个您想要编译的容器,代码将无法编译
能够使用。将要编译的代码更隐蔽
罪魁祸首是迭代器无效的不同规则,
适用于不同序列容器的指针和引用。
要编写能够正确使用vector、deque和list的代码,您需要
必须假定任何使迭代器、指针或
任何容器中的引用都会使容器中的引用无效
你正在使用。因此,您必须假设每个对insert的调用都会使所有内容无效,因为deque::insert会使所有迭代器无效,
由于缺乏调用容量的能力,vector::insert必须假定为
使所有指针和引用无效。(第1项说明deque是
独特之处在于有时使其迭代器无效,而不使其迭代器无效
指针和参考。)类似的推理得出结论
必须假设每个擦除调用都会使所有内容无效
还要吗?[是的,这一项目继续下去,继续下去,继续下去。]
目标是什么?在什么情况下向量、集合和映射是可互换的?您可以创建类型特征,并为每个类似xxx的类型指定一个函数专门化。这可以