Can SFINAE be used to select an overload of a template method within a template class?

44 views Asked by At

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?

0

There are 0 answers