C中模板选择的优先级
我刚写了下面这段代码
template<typename T> inline bool contains(T haystack,typename T::key_type needle) { return haystack.find(needle) != haystack.end(); } template<typename T> inline bool contains(T haystack,typename T::value_type needle) { return find(haystack.begin(),haystack.end(),needle) != haystack.end(); } 当我使用没有key_type typedef的vector实例化模板时,SFINAE会确保我不会实例化第一个版本.但是,如果我使用具有key_type和value_type typedef的映射来实例化模板呢?编译器如何选择使用哪个模板函数? 使用当前的STL映射,key_type是一对,但是如果我定义key_type与value_type相同的类型会发生什么? class MyMap {typedef int key_type;typedef int value_type;}; MyMap m; contains(m,1); // both functions are valid,which will be chosen? 令人惊讶的是,std :: set有key_type == value_type.所以我真的需要求助于模板元编程才能拥有一个简单的包含函数.叹. 引用标准的奖励点. 解决方法
如果你愿意这样做,你可以通过一些元编程帮助你.基本上你需要编写一个模板元函数来确定你想要调用一个或另一个函数的条件,并在enable_if_c子句中使用它:
template <typename T> inline typename enable_if_c< has_key_type<T>::value,bool >::type contains( T const & c,T::key_type const & k ) {...} // associative container template <typename T> inline typename enable_if_c< !has_key_type<T>::value,T::value_type const & k ) {...} // non-associative container enable_if_c模板是一个简单的常见SFINAE技巧(可以从C 0x编译器或boost中使用).它需要一个条件和一个类型,如果条件为真,它将为参数类型生成一个内部typedef,如果它不存在则不会定义该内部类型,并且可以在SFINAE外部使用: template <bool condition,typename T> struct enable_if_c {}; // by default do not declare inner type template <typename T> struct enable_if_c<true,T> { // if true,typedef the argument as inner type typedef T type; }; 现在有趣的部分是如何确定类型T具有内部类型key_type,虽然可能有其他选项,但首先想到的是: template <typename T> class has_key_type { typedef char _a; struct _b { _a x[2]; }; template <typename U> static _a foo( U const &,typename U::key_type* p = 0 ); static _b foo( ... ); static T& generate_ref(); public: static const bool value = sizeof(foo(generate_ref())) == sizeof(_a); }; 模板has_key_type将包含一个内部常量值,仅当传递的int类型包含内部T :: key_type类型时才为true.解决方案并不太复杂:定义一个模板函数,它对于所有类型都会失败,但是你想要检测的模板函数,并提供带有省略号的不同重载,以便在模板(具有比省略号更高的优先级)失败时捕获它替代.然后使用返回类型的大小来检测编译器选择的重载. generate_ref用于避免必须实际构造对象(即,不强加T可以以任何特定方式构造). 总体结果是当类型T包含内部类型key_type时,has_key_type< T> :: value的结果将为true,并且enable_if_c将启用第一个重载并禁用第二个,因此SFINAE将丢弃第二个重载而不是因为没有定义类型的第二个函数参数,而是返回类型的术语. 如果你想到它,只有一堆锅炉板代码围绕一个小的变化:而不是提供两个模糊的模板函数重载,提供模板重载和较低优先级的功能(省略号).由于您无法真正使用该省略号函数来实现非关联容器版本,因此它用于获取布尔值,然后将其接种到公共元编程结构和样板文件中. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |