JamesR
JamesR

Reputation: 363

C++ Compiler Error (trying to create a static vector of vectors)

I'm trying to create a static vector-of-vectors and I'm finding that the following code compiles and runs under gcc-4.1.2 but under gcc-4.5.1 it fails to compile with the message

assign.cxx:19:48: error: no matching function for call to ‘to(boost::assign_detail::generic_list<std::basic_string<char> >&)’

Can anyone explain why this happens? If you have any other suggestions about how to do what I'm trying to do then I'd be happy with that instead :).

#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>

template <template <typename> class containerType, typename elemType>
containerType<elemType> to( boost::assign_detail::generic_list<elemType> list ) {
  containerType<elemType> tempContainer = list;
  return tempContainer;
}

static const std::vector<std::vector<std::string> > names = boost::assign::list_of
  (to<std::vector>(boost::assign::list_of<std::string>("A")("B")("C") ))
  (to<std::vector>(boost::assign::list_of<std::string>("D")("E")("F") ));

int main() {

  for( std::vector< std::vector<std::string> >::const_iterator itVec = names.begin(); itVec != names.end(); ++itVec ) {
    for( std::vector<std::string>::const_iterator itStr = itVec->begin(); itStr != itVec->end(); ++itStr ) {
      std::cout << "Value is " << *itStr << std::endl;
    }
  }
  return 0;
}

Upvotes: 1

Views: 798

Answers (3)

ildjarn
ildjarn

Reputation: 63005

The problem stems from the fact that in your definition of to<>(), containerType is declared to have only one template parameter, when in fact std::vector<> has two template parameters.

The fact that this compiles in GCC 4.1.2 only indicates a bug in GCC 4.1.2 -- the code is still inherently incorrect.

Unfortunately, I can't think of a good workaround offhand. The following compiles but restricts you to containers with only two template arguments (wherein the second is the allocator), which may not be what you ultimately want:

#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>

template<
  template<typename, typename> class containerType,
  typename allocatorType,
  typename elemType
>
containerType<elemType, allocatorType >
to(boost::assign_detail::generic_list<elemType> const& list)
{
  return list; // no need to explicitly construct a containerType instance
}

template<template<typename, typename> class containerType, typename elemType>
containerType<elemType, std::allocator<elemType> >
to(boost::assign_detail::generic_list<elemType> const& list)
{
  return to<containerType, std::allocator<elemType> >(list);
}

static std::vector<std::vector<std::string> > names = boost::assign::list_of
  (to<std::vector>(boost::assign::list_of<std::string>("A")("B")("C")))
  (to<std::vector>(boost::assign::list_of<std::string>("D")("E")("F")));

int main()
{
  typedef std::vector<std::vector<std::string> >::const_iterator outer_iter_t;
  typedef std::vector<std::string>::const_iterator inner_iter_t;

  for (outer_iter_t itVec = names.begin(); itVec != names.end(); ++itVec)
    for (inner_iter_t itStr = itVec->begin(); itStr != itVec->end(); ++itStr)
      std::cout << "Value is " << *itStr << '\n';
}

EDIT (in response to dribeas' comment): Updated to allow the caller to override the default allocator.

Upvotes: 3

After going around the problem a couple of things, I believe that the simplest solution is not using a template template argument, but rather a type template argument:

template <typename containerType, typename elemType>
containerType to( boost::assign_detail::generic_list<elemType> list ) {
  containerType tempContainer = list;
  return tempContainer;
}

static const std::vector<std::vector<std::string> > names = boost::assign::list_of
  (to<std::vector<std::string> >(boost::assign::list_of<std::string>("A")("B")("C") ))
  (to<std::vector<std::string> >(boost::assign::list_of<std::string>("D")("E")("F") ));

It might require a bit more typing in the calling side, but it will take care of the extra template arguments that you are not declaring in your template template argument.

Upvotes: 1

neodelphi
neodelphi

Reputation: 2786

Your call to the function to<std::vector>( ... ) only contains one template parameter, whereas you function declaration contains two. I would try: to<std::vector, std::string>( ... )

Upvotes: -1

Related Questions