I'm attempting to apply SFINAE in C++03 to a std::vector
clone (for educational purposes) in order to restrict the type of iterator passed to the constructor:
struct input_iterator_tag {};
struct output_iterator_tag {};
struct InputIter {
typedef input_iterator_tag iterator_category;
};
struct OutputIter {
typedef output_iterator_tag iterator_category;
};
template<class T>
class Vector {
public:
explicit Vector(size_t, T=T());
template <class InputIt>
Vector(InputIt, InputIt, input_iterator_tag = typename InputIt::iterator_category());
};
template<class T>
Vector<T>::Vector(size_t, T)
{
std::cout << "size_t overload called" << std::endl;
}
template<class T>
template <class InputIt>
Vector<T>::Vector(InputIt, InputIt, input_iterator_tag)
{
std::cout << "input iterator overload called" << std::endl;
}
int main(int argc, char* argv[])
{
InputIter input;
OutputIter output;
Vector<int> a(0, 0);
Vector<int> b(input, input);
// Should fail to compile:
Vector<int> c(output, output);
}
The compiler (g++-4.9) correctly rejects the definition of vector c
(passed the wrong type of iterator), but also rejects the definition of vector a
, failing with:
sfinae.cpp: In constructor 'Vector<T>::Vector(InputIt, InputIt, input_iterator_tag) [with InputIt = int; T = int]':
sfinae.cpp:42:23: error: 'int' is not a class, struct, or union type
Vector<int> a(0, 0);
^
sfinae.cpp:42:23: note: when instantiating default argument for call to Vector<T>::Vector(InputIt, InputIt, input_iterator_tag) [with InputIt = int; T = int]
Why is the substitution failure classified as an error here?