我想使用::iterator
成员类型将c ++容器解析为另一个对象。迭代器成员类型指向单个类型的对象(向量,队列等)的容器将变为类似列表的对象,而迭代器成员类型指向std::pair
的容器将变为映射 - 喜欢对象。
我正在尝试编写一个成员函数来检测后一种容器,但它不起作用。这是我到目前为止所做的:
#include <tuple>
#include <iterator>
#include <type_traits>
template <typename T>
struct is_pair : std::false_type { };
template <typename T, typename U>
struct is_pair<std::pair<T, U>> : std::true_type { };
template <typename T>
constexpr bool is_pair_v = is_pair<T>::value;
template <typename...>
struct is_mapping : std::false_type { };
template <typename Container>
struct is_mapping<Container, std::enable_if_t<
is_pair_v<std::iterator_traits<typename Container::iterator>::value_type>
>> : std::true_type { };
template <typename T>
constexpr bool is_mapping_v = is_mapping<T>::value;
#include <map>
#include <vector>
#include <iostream>
int main() {
std::cout << "is_pair:" << std::endl;
std::cout << "Map: " << is_pair_v<std::iterator_traits<std::map<int, int>::iterator>::value_type> << std::endl;
std::cout << "Vector: " << is_pair_v<std::iterator_traits<std::vector<int>::iterator>::value_type> << std::endl;
std::cout << std::endl;
std::cout << "is_mapping:" << std::endl;
std::cout << "Map: " << is_mapping_v<std::map<int, int>> << std::endl;
std::cout << "Vector: " << is_mapping_v<std::vector<int>> << std::endl;
}
出于某种原因,is_mapping_v
始终为false,代码会生成此输出:
$ g++ -std=c++14 temp.cc && ./a.out
is_pair:
Map: 1
Vector: 0
is_mapping:
Map: 0
Vector: 0
我的代码出了什么问题?
注意:这不是Checking if a type is a map的副本。该问题的答案使用::key_type
和::mapped_type
成员来检测地图(对std::multimap
等类失败。我也明确地使用迭代器稍后在我的代码中指向std::pair
的事实,因此检查它会更有意义。
答案 0 :(得分:5)
is_pair_v<std::iterator_traits<typename Container::iterator>::value_type>
应该是
is_pair_v<typename std::iterator_traits<typename Container::iterator>::value_type>
因为value_type
是一种类型。如果没有typename
,它将被解析为值并使enable_if
失败,从而回退到主模板。
main
中的测试产生正确值的原因是因为那里的模板已经被实例化,并且value_type
是类型还是值没有歧义。
第二个错误是您的主要模板
template<typename...>
应该是
template<typename, typename = void>
否则,is_mapping<T>
永远不会是两个参数的专门化,因为参数计数不匹配。
答案 1 :(得分:2)
编译器没有选择部分专用的结构。这有两个原因:
enable_if
开始is_pair_v<std::iterator_traits<typename Container::iterator>::value_type>
。编译器会将std::iterator_traits<...>::value_type
视为一个值而不是一个类型,但是SFINAE会启动,而这只是默默删除。使用template <typename...>
使其无法选择特化。如果我是对的,这是因为is_mapping<T>
可以使用初始定义解析为is_mapping<T>
,或使用专业化解析is_mapping<T, void>
。在这种情况下,is_mapping<T>
似乎是首选。
修复此问题就像将其更改为template <typename, typename = void>
:
template <typename, typename = void>
struct is_mapping : std::false_type { };
template <typename Container>
struct is_mapping<Container, std::enable_if_t<
is_pair_v<typename std::iterator_traits<typename Container::iterator>::value_type>
>> : std::true_type { };
然而,is_mapping
的更简单实现将是:
template <typename Container>
struct is_mapping : is_pair<
typename std::iterator_traits<typename Container::iterator>::value_type
> {};
基本上,您的版本看起来像
if (is_pair(...)) return true;
else return false;
而你可以简单地做
return is_pair(...)