I want to write a class that takes a pair of iterators as parameters to the constructor, but I dont know how to raise an error at compile-time when those iterators' value_type
doesn't match an expected type. This is what I tried using 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
}
Note that in this case, int
to double
would be fine, but thats just an example and in the real code the types have to match exactly. To my surprise in both cases, the constructor works without errors (there is only a warning about the unused typedef). Does the -1
sized array static assert trick not work when the typedef is declared inside a method? How do I produce an error when IT::value_type
is the wrong type?
PS: would be nice if there was an easy C++98 solution, but if this gets too complicated, I could also accept a C++11 solution.
In modern C++, you could have used std::is_same
and static_assert
:
static_assert(std::is_same_v<typename std::iterator_traits<IT>::value_type, double>,
"wrong iterator");
See also std::iterator_traits
: an iterator it
is not guaranteed to have a value_type
typedef, and one should use std::iterator_traits<it>::value_type
instead.
In C++ 98, is_same
is trivial to implement, static_assert
needs a negative-size array trick or the BOOST_STATIC_ASSERT
.