Search code examples
c++iteratortypecheckingc++98static-assert

How to allow only iterators with a ceratin value_type?


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.


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.