Template template parameters and variadic templates with gcc 4.4

Faheem Mitha picture Faheem Mitha · Dec 15, 2011 · Viewed 7.8k times · Source

I'm using gcc 4.4 on Debian squeeze. Consider the following code.

#include <map>
#include <string>
using std::map;
using std::string;

// Args lets the user specify additional explicit template arguments
template <typename T,
      template <typename T, typename... Args> class C,
      typename... Args>
C<T, Args...> foo()
{
  C<T, Args...> x;
  return x;
}

int main(void)
{
  map<string, int> a = foo<string, map, int>();
}

So, the idea here is that T matches string, C matches map, and the template parameter pack Args matches int. I may have some of the syntax wrong, please correct if so. In particular, if one wants the first template argument in class C to match T and the rest to match the template parameter pack Args, is template <typename T, typename... Args> class C the correct syntax?

This gives the error

In function 'int main()':
post.cc:18: error: no matching function for call to 'foo()'

This appears to be similar to the question Variadic template templates and perfect forwarding. That question suggests that this is a gcc bug, but maybe I am mistaken in thinking these questions are about the same thing.

Please be gentle. My knowledge of variadic templates is less than 12 hours old; I was just trying to rewrite some old C++ code to reduce duplication. It has also been a while since I did any C++. If there is a workaround, please let me know. Thanks.

EDIT: The workaround suggested in the comments of Variadic template templates and perfect forwarding by Ise Wisteria worked for me, which suggests that this is the same bug. Of course, I'm am now (a) wondering how fragile this workaround is and (b) why it works, and what motivated Ise to think of it. Though I guess only Ise can answer the last bit. :-)

Answer

Faheem Mitha picture Faheem Mitha · Dec 15, 2011

As discussed in the edits, my question appears to tickle the same bug as the linked question, Variadic template templates and perfect forwarding. In particular, the workaround given there in a link also works in my case. The modified code that works is as follows:

#include <map>
#include <string>
using std::map;
using std::string;

template <typename T,
      template <typename T, typename... Args> class C,
      typename... Args>
struct X
{
  typedef C<T, Args...> type;
};

template <typename T,
      template <typename T, typename... Args> class C,
      typename... Args>
typename X<T, C, Args...>::type foo()
{
  C<T, Args...> x;
  return x;
}

int main(void)
{
  map<string, int> a = foo<string, map, int>();
}