Hind Forsum
Hind Forsum

Reputation: 10497

c++: why template cannot be used to deduce both container and element type?

I've got a very simple test program like below:

#include<vector>
#include<iostream>
using namespace std;
template<typename C, typename E>
void f(const C<E>& container){
    cout<<container.size()<<endl;
}
int main(){
    vector<int> i;
    f(i);
    return 0;
}

It fails to compile with gcc 4.1.2. Error message is:

templateContainer.cpp:5: error: ‘C’ is not a template
templateContainer.cpp: In function ‘int main()’:
templateContainer.cpp:10: error: no matching function for call to ‘f(std::vector<int, std::allocator<int> >&)’

Upvotes: 4

Views: 1364

Answers (3)

Useless
Useless

Reputation: 67723

Although WhiZTiM's answer is correct (well, preferring the second part), it doesn't explain why your code doesn't work.

Assuming for the moment that you intended roughly

template<template <typename> class C, typename E> void f(const C<E>&);

the reason that std::vector doesn't match is that it is the wrong shape - it has two type parameters, not one as in your declaration.

Just because you don't often explicitly write the defaulted second (allocator) param, doesn't mean it isn't there.

For comparison, this works (or doesn't) in an analogous way:

void f(int);
void g(int, int* = nullptr);

void apply(void (*func)(int), int);

apply(f, 42); // ok - f matches shape void(*)(int)
apply(g, 42); // error - g is really void(*)(int,int*)

specifically, default arguments (or type parameters) are syntactic sugar. They allow you to forget about those arguments at the call (instantiation) site, but don't change the shape of the function (or template).

Upvotes: 2

0xBADF00
0xBADF00

Reputation: 1120

std::vector has two template arguments, type and allocator.

template <template<class, class> class C, class E, class A>
void f(const C<E, A> &container) 
{
   std::cout << container.size() << endl;
}

int main()
{
   std::vector<int> i;
   f(i);
   return 0;
}

Upvotes: 2

WhiZTiM
WhiZTiM

Reputation: 21576

You could use a template template parameter (and note that std::vector actually takes more than one template parameter [an element type, and an allocator type]).:

template<template <typename...> class C, typename... E>
void f(const C<E...>& container){
    cout<<container.size()<<endl;
}

Live Demo


If you don't need the type decompositions, you could simply use an ordinary template.

template<typename C>
void f(const C& container){
    cout<<container.size()<<endl;
}

You can additionally obtain typedefs from STL containers: for example, if you want to know the type of elements held by the container, value_type is there for you.

template<typename C>
void f(const C& container){
    using ValueType = typename C::value_type;
    cout<<container.size()<<endl;
}

Upvotes: 12

Related Questions