Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

template template parameters not working with STL containers

443 views
Skip to first unread message

vl106

unread,
Feb 18, 2009, 8:26:29 AM2/18/09
to
The code sample below is not working. It is taken from
Nicolai Josuttis "C++ Templates: The Complete Guide".
In the chapter 5.4 Template Template Parameters it reads
[slightly stripped]:

#include <deque>

template <typename T>
class MyVector {
public:
void push_back(T const&) {}
};

template <typename T, template <typename> class CONT = /*MyVector*/
std::deque >
class Stack {
private:
CONT<T> elems; // elements
public:
void push(T const&); // push element
};

template <typename T, template <typename> class CONT>
void Stack<T,CONT>::push(T const& elem)
{
elems.push_back(elem); // append copy of passed elem
}

int main() {
Stack<int> iStack;
iStack.push(1);
return 0;
}

With Visual Studio 2005 I get the following error message:

error C3201: the template parameter list for class template
'std::deque' does not match the template parameter list for template
parameter 'CONT'
error C3201: the template parameter list for class template
'std::deque' does not match the template parameter list for template
parameter 'CONT'
error C2976: 'std::deque' : too few template arguments
deque(486) : see declaration of 'std::deque'

The problems is not the template template parameter itself.
When I substitute the default argument with "MyVector" the
code compiles fine.

How do I have to modify the sample to make it work with the
original STL containers std::deque, std::vector, ...

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Bo Persson

unread,
Feb 19, 2009, 2:09:18 AM2/19/09
to
vl106 wrote:
> The code sample below is not working. It is taken from
> Nicolai Josuttis "C++ Templates: The Complete Guide".
> In the chapter 5.4 Template Template Parameters it reads
> [slightly stripped]:
>
> #include <deque>
>
> template <typename T>
> class MyVector {
> public:
> void push_back(T const&) {}
> };
>
> template <typename T, template <typename> class CONT = /*MyVector*/
> std::deque >
> class Stack {
> private:
> CONT<T> elems; // elements
> public:
> void push(T const&); // push element
> };
>
>
> With Visual Studio 2005 I get the following error message:
>
> error C3201: the template parameter list for class template
> 'std::deque' does not match the template parameter list for template
> parameter 'CONT'
> error C3201: the template parameter list for class template
> 'std::deque' does not match the template parameter list for template
> parameter 'CONT'
> error C2976: 'std::deque' : too few template arguments
> deque(486) : see declaration of 'std::deque'
>
> The problems is not the template template parameter itself.
> When I substitute the default argument with "MyVector" the
> code compiles fine.
>
> How do I have to modify the sample to make it work with the
> original STL containers std::deque, std::vector, ...


The error messages actually tells you what the problem is:

The problem is that std::deque and std::vector also has additional
default template arguments. You require a template with a single
argument, so the standard containters do not match.


Bo Persson

Mathias Gaunard

unread,
Feb 19, 2009, 2:08:31 AM2/19/09
to
On 18 fév, 14:26, vl106 <vl...@hotmail.com> wrote:
> The code sample below is not working.
> [...]

> template <typename T, template <typename> class CONT = /*MyVector*/
> std::deque >

std::deque takes three template parameters, not one.

Pavel Minaev

unread,
Feb 19, 2009, 2:13:53 AM2/19/09
to

Well, you seem to be using a good compiler - it told you what to do
right there! Indeed, just look at the declaration of std::deque:

template <typename T, typename Allocator = std::allocator<T> >
class deque { ... };

As you can see, it has two template arguments, and not one. True, the
second one has a default value, so you mostly only care about the
first argument - but it's not good enough in this case.

The obvious fix is to change your template correspondingly, probably
something along the lines of:

template <typename T, template <typename, typename> class CONT =
std::deque, typename Allocator>
class Stack { ... };

And, of course, consider using a C++ book that's more up-to-date with
respect to the C++ standard.

poking su

unread,
Feb 19, 2009, 2:13:53 AM2/19/09
to
在 2009-02-18三的 07:26 -0600,vl106写道:

You must know that std::deque is also a template,but your template
Stack's second argument does not make deque defined correctly,
so maybe you can try this:


template <typename T, template <typename> class CONT = /*MyVector*/

std::deque<T> >

SG

unread,
Feb 19, 2009, 2:13:51 AM2/19/09
to
On 18 Feb., 14:26, vl106 <vl...@hotmail.com> wrote:
> template <typename T,
> template <typename> class CONT = std::deque>
>
> [...]

>
> error C3201: the template parameter list for class template
> 'std::deque' does not match the template parameter list for template
> parameter 'CONT'

This is because std::deque is a class template that takes more than
one template parameter "typename T". It also takes an allocator
"class Alloc".

For reasons I'm not aware of the C++ standard says that you can't pass
such a class template -- even with a default allocator type -- as a
template template parameter that only takes one template parameter.

This is probably one reason why template template parameters are not
so popular. In future C++ you will be able to do a "template typedef"

template<typename T>
using vector_with_standard_alloc = std::vector<T>;

so you can use "vector_with_standard_alloc" as default template
argument. Another workaround is to define your own container class
template with only one template parameter (like MyVector).

Cheers!
SG

red floyd

unread,
Feb 19, 2009, 2:13:33 AM2/19/09
to
On Feb 18, 5:26 am, vl106 <vl...@hotmail.com> wrote:

std::deque has *two* template parameters. Therefore it doesn't match
your template template class parameter.

David Abrahams

unread,
Feb 19, 2009, 1:55:39 PM2/19/09
to

on Wed Feb 18 2009, vl106 <vl106-AT-hotmail.com> wrote:

> The code sample below is not working. It is taken from
> Nicolai Josuttis "C++ Templates: The Complete Guide".
> In the chapter 5.4 Template Template Parameters it reads
> [slightly stripped]:
>
> #include <deque>
>
> template <typename T>
> class MyVector {
> public:
> void push_back(T const&) {}
> };
>
> template <typename T, template <typename> class CONT = /*MyVector*/> std::deque >

<snip>

Others have explained the problem; I can offer some alternative
solutions:

1. Metafunction Class:

// Create one of these for each container type
struct make_deque
{
template <class T>
struct apply
{
typedef std::deque<T> type;
};
};

template <typename T, typename GenCont = make_deque>
class Stack {
private:
typename GenCont<T>::type elems; // elements


public:
void push(T const&); // push element
};

2. MPL Lambda Expression:

#include <boost/mpl/apply.hpp>
#include <boost/mpl/placeholders.hpp>
namespace mpl = boost::mpl;

template <typename T, typename GenCont = std::deque<mpl::_> >
class Stack {
private:
typename mpl::apply<GenCont,T>::type elems;
public:
void push(T const&);
};

See http://www.boost.org/libs/mpl and http://www.boostpro.com/mplbook
for more info.

Regards,

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Nikola Smiljanić

unread,
Feb 19, 2009, 1:59:08 PM2/19/09
to
> [ Seehttp://www.gotw.ca/resources/clcm.htmfor info about ]

> [ comp.lang.c++.moderated. First time posters: Do this! ]

You should have kept reading the book. Because he explains everything
about this problem and gives a solution. Quote:

If you try to use the new version of Stack, you get an error message
saying that the default value std::deque is not compatible with the
template template parameter CONT. The problem is that a template
template argument must be a template with parameters that exactly
match the parameters of the template template parameter it
substitutes. Default template arguments of template template arguments
are not considered, so that a match cannot be achieved by leaving out
arguments that have default values.

The problem in this example is that the std::deque template of the
standard library has more than one parameter: The second parameter
(which describes a so-called allocator) has a default value, but this
is not considered when matching std::deque to the CONT parameter.

There is a workaround, however. We can rewrite the class declaration
so that the CONT parameter expects containers with two template
parameters:

template <typename T,
template <typename ELEM,
typename ALLOC = std::allocator<ELEM> >
class CONT = std::deque>


class Stack {
private:
CONT<T> elems; // elements


};

gpderetta

unread,
Feb 19, 2009, 8:46:33 PM2/19/09
to
On 19 Feb, 19:55, David Abrahams <d...@boostpro.com> wrote:
> // Create one of these for each container type
> struct make_deque
> {
> template <class T>
> struct apply
> {
> typedef std::deque<T> type;
> };
> };
>
> template <typename T, typename GenCont = make_deque>
> class Stack {
> private:
> typename GenCont<T>::type elems; // elements

typename GenCont::template apply<T>::type elems;

You forgot the extra level of indirection ;)

--
Giovanni P. Deretta


--

0 new messages