如何仅允许带有 ceratin value_type的迭代器
How to allow only iterators with a ceratin value_type?
我想编写一个将一对迭代器作为构造函数参数的类,但是当这些迭代器的value_type
与预期类型不匹配时,我不知道如何在编译时引发错误。这是我尝试使用typeid
#include <vector>
struct foo {
std::vector<double> data;
template <typename IT>
foo(IT begin, IT end){
typedef int static_assert_valuetype_is_double[
typeid(typename IT::value_type) == typeid(double) ? 1 : -1
];
std::cout << "constructor called n";
data = std::vector<double>(begin,end);
}
};
int main()
{
std::vector<double> x(5);
foo f(x.begin(),x.end()); // double: ok
std::vector<int> y(10);
foo g(y.begin(),y.end()); // int: should not compile
}
请注意,在这种情况下,int
double
就可以了,但这只是一个示例,在实际代码中,类型必须完全匹配。令我惊讶的是,在这两种情况下,构造函数都没有错误地工作(只有关于未使用的 typedef 的警告(。在方法中声明 typedef 时,-1
大小的数组静态断言技巧是否不起作用?当IT::value_type
类型错误时如何产生错误?
PS:如果有一个简单的 C++98 解决方案会很好,但如果这太复杂,我也可以接受 C++11 解决方案。
在现代C++中,您可以使用std::is_same
和static_assert
:
static_assert(std::is_same_v<typename std::iterator_traits<IT>::value_type, double>,
"wrong iterator");
另请参阅std::iterator_traits
:迭代器it
不能保证具有value_type
typedef,应该改用std::iterator_traits<it>::value_type
。
在 C++ 98 中,实现起来is_same
微不足道,static_assert
需要一个负大小的数组技巧或BOOST_STATIC_ASSERT
。
对于在 C++98 及更高版本中工作的解决方案.....
#include <iterator>
template<class T> struct TypeChecker
{};
template<> struct TypeChecker<double>
{
typedef double valid_type;
};
template <typename IT>
void foo(IT begin, IT end)
{
typename TypeChecker<typename std::iterator_traits<IT>::value_type>::valid_type type_checker;
(void)type_checker;
// whatever
}
对于value_type
double
的迭代器,foo()
的实例化将成功,否则无法编译。
前提是TypeChecker<x>
没有除double
以外的任何x
的valid_type
,但我们尝试在foo()
中实例化该类型的实例。 该(void)type_checker
可防止某些编译器对有效类型发出有关从未使用的变量的警告。
这是实现它的 C++98 兼容方法.....
首先是有趣的部分:实现is_same
相当简单
template <typename T,typename U> struct is_same_type { static const bool value; };
template <typename T,typename U> const bool is_same_type<T,U>::value = false;
template <typename T> struct is_same_type<T,T> { static const bool value; };
template <typename T> const bool is_same_type<T,T>::value = true;
现在,不太有趣的部分(C++11确实有助于静态断言而不会引起同事的注意(:
struct foo {
std::vector<double> data;
template <typename IT>
foo(IT begin, IT end) : data(begin,end) {
typedef int static_assert_valuetype_is_double[
is_same_type<double,typename IT::value_type>::value ? 1 : -1
];
std::cout << "constructor called n";
}
};
int main(){
std::vector<double> x(5,2.3);
foo f(x.begin(),x.end());
for (std::vector<double>::iterator it = f.data.begin(); it != f.data.end();++it) std::cout << *it << " ";
//std::vector<int> y(10,3);
//foo g(y.begin(),y.end()); // THIS FAILS (AS EXPECTED)
}
正如其他人指出的那样,我实际上应该使用std::iterator_traits<IT>::value_type
因为并非每个迭代器都有value_type
。但是,就我而言,我宁愿将可能的迭代器限制为一小组,在我的特定情况下,不允许没有value_type
的迭代器不是问题。
还要注意的是,问题中的代码分配给成员,而使用初始值设定项列表当然更好。
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 如何在c++迭代器类型中包装std::chrono
- 集合上的输出迭代器:assign和increment迭代器
- Boost Spirit,获取迭代器内部语义动作
- 对于set上的循环-获取next元素迭代器
- 为什么output_editor Concept不需要output_e迭代器标记
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 使用迭代器时如何访问对象在向量中的位置?
- std::vector::迭代器是否可以合法地作为指针
- 跟随整数索引列表的自定义类迭代器
- 不明白迭代器,引用和指针失效,一个例子
- 我可以使用反向迭代器作为ForwardIt吗
- ESP8266单片机矢量迭代器的C++问题
- 迭代器的声明:"does not contain a type"
- 如何在C++中获取任意 (STL) 输出迭代器的"assignable type"
- 从Range Type中获取迭代器类型
- 在映射对象上定义自定义迭代器:神秘的"incomplete type"错误
- "Unresolved overloaded function type"尝试将for_each与迭代器一起使用并在C++中发挥作用