Mr.Anubis
Mr.Anubis

Reputation: 5342

Templates instantiation confusion

This is my code to check whether class has member function begin or not :

template<typename T> struct has_begin
{
    struct dummy {typedef void const_iterator;};
    typedef typename std::conditional< has_iterator<T>::yes, T, dummy>::type TType;
    typedef typename TType::const_iterator Iter;
    struct fallBack{ Iter begin() const ; Iter end() const;};
    struct checker : T, fallBack {};
    template <typename B, B> struct cht;
    template<typename C> static char check(cht< Iter (fallBack::*)() const, &C::begin>*); // problem is here
    template<typename C> static char (&check(...))[2];
public:
    enum {no = (sizeof(check<checker>(0))==sizeof(char)),
     yes=!no};
};

If I change second argument of cht in check(cht< Iter (fallBack::*)() const, &C::begin>*); to &checker::begin , This doesn't changes the semantic of code since cht's second template argument is always checker due to this enum {no = (sizeof(check<checker>(0))==sizeof(char))

but code change results in error now which are :

prog.cpp: In instantiation of 'has_begin<std::vector<int> >':
prog.cpp:31:51:   instantiated from here
prog.cpp:23:38: error: reference to 'has_begin<std::vector<int> >::checker::begin' is ambiguous

I want to know what is the reason behind this behavior.

Upvotes: 7

Views: 266

Answers (1)

wolfgang
wolfgang

Reputation: 4953

from the Wikipedia article about SFINAE - Substitution Failure is Not An Error:

[...] when creating a candidate set for overload resolution, some (or all) candidates of that set may be the result of substituting deduced template arguments for the template parameters. If an error occurs during substitution, the compiler removes the potential overload from the candidate set instead of stopping with a compilation error [...]

In your code as posted, an ambiguity error occurs while instantiating the function template check with parameter C == typename has_begin<T>::checker, and that substitution leads to the error, so the instantiation is simply removed from the overload set.

If you change your code, a similar ambiguaty error occurs with &checker::begin. This time, however, it is not the result of substituting the template parameter C for the check function template. The subsitution of the template parameter T of struct has_begin is not relevant for the SFINAE rule, as that template has already been successfully instantiated.

Upvotes: 3

Related Questions