user2953119
user2953119

Reputation:

Understanding template argument deduction

Consider the following code:

#include <vector>

template <typename T>
using v_itt = typename std::vector<T>::iterator;

template <typename T>
void foo(v_itt<T>){ }

int main() {
    typename std::vector<long>::iterator i = std::vector<long>().begin();
    foo(i); //candidate template ignored: couldn't infer template argument 'T'
}

DEMO

What's wrong with the code? I thought the T should have been deduced to long. Is there a way to fix that somehow?

Upvotes: 9

Views: 133

Answers (2)

Paolo M
Paolo M

Reputation: 12757

I'd like just to add a possible workaround 3 to Marco's answer:

#include <vector>

template<typename T>
void real_foo( typename std::vector<T>::iterator){}

template <typename T>
void foo(T i){ real_foo<typename decltype(i)::value_type>(i); }

int main() {
    std::vector<long> v;
    foo(v.begin());
}

Upvotes: 4

Marco A.
Marco A.

Reputation: 43662

typename std::vector<T>::iterator

iterator (a dependent type) it is not deducible in your code since it is in a nested name specifier and the standard says

§14.8.2.5/4

In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

and §14.8.2.5/5

The non-deduced contexts are:

— The nested-name-specifier of a type that was specified using a qualified-id.

so this is a non-deduced context.

Possible workarounds:

  1. Pass a vector reference instead of an iterator
  2. Use tag dispatching and compile time assertions to verify your iterator

Upvotes: 5

Related Questions