14

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. :-)

Community
  • 1
  • 1
Faheem Mitha
  • 6,096
  • 7
  • 48
  • 83
  • The code compiles on g++ 4.7. Should be a bug. – kennytm Dec 15 '11 at 03:26
  • @KennyTM: Thanks. That means I don't need to report it, right? – Faheem Mitha Dec 15 '11 at 03:33
  • So, what do you want to happen to this question? Close as duplicate? Maybe answer your own question? :) This can't be left as is. – Xeo Dec 15 '11 at 04:06
  • @Xeo: So, it is definitely a duplicate of the linked question in your opinion? If so, I don't have strong feelings. Would it be Ok if I answered it and then accepted my answer? Unless you or someone else would rather. :-) If it is closed, will it still be visible to people doing searches? – Faheem Mitha Dec 15 '11 at 04:16
  • Not exactly, but the problem is the same, aswell as the answer. I don't really care though, might aswell go ahead and answer your own question. :) – Xeo Dec 15 '11 at 04:17

2 Answers2

4

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>();
}
Community
  • 1
  • 1
Faheem Mitha
  • 6,096
  • 7
  • 48
  • 83
0

I don't think variadic template parameters can match non-variadic arguments in g++4.4, so you need to overload your foo function with a non-variadic version.

Also keep in mind that map actually has more than two template parameters, and therefor wont match the new foo-function either.

This addition to your example should clarify it:

#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;
}

template<typename T, template<typename, typename> class C, typename Arg>
C<T, Arg> foo() {
  return C<T, Arg>();
}

template<typename T, typename... Args> class A {};

template<typename T, typename Arg> class B {};

int main(void) {
  map<string, int> a = foo<string, map, int>(); // fails.
  A<string, int> x = foo<string, A, int>();
  B<string, int> y = foo<string, B, int>();
}
masaers
  • 697
  • 9
  • 21
  • No, variadic templates are explicitly able to match nonvariadic templates. – Xeo Dec 15 '11 at 03:34
  • Well, that's a bug. I'm talking about what the standard says. "I don't think variadic template parameters can match non-variadic arguments" seemed to suggest that you think this is the case in general. – Xeo Dec 15 '11 at 03:42
  • 1
    @Xeo: Fair enough. I'll edit the answer to reflect your point. – masaers Dec 15 '11 at 03:43