Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 214
Mr.Anubis Avatar asked Dec 15 '11 10:12

Mr.Anubis


People also ask

What is the main problem with templates?

There are two main reasons why people dislike templates: They're confusing. They can lead to long compilation times.

Is it necessary to instantiate a template?

In order for any code to appear, a template must be instantiated: the template arguments must be provided so that the compiler can generate an actual class (or function, from a function template).

How do I force a template instantiation?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.

What happens when a class template is instantiated?

Template instantiation involves generating a concrete class or function (instance) for a particular combination of template arguments. For example, the compiler generates a class for Array<int> and a different class for Array<double>.


1 Answers

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.

like image 127
wolfgang Avatar answered Sep 18 '22 08:09

wolfgang