10

I've prepared a simple variadic template test in Code::Blocks, but I'm getting an error:

No matching function for call to 'OutputSizes()'

Here's my source code:

#include <iostream>
#include <typeinfo>

using namespace std;

template <typename FirstDatatype, typename... DatatypeList>
void OutputSizes()
{
    std::cout << typeid(FirstDatatype).name() << ": " << sizeof(FirstDatatype) << std::endl;
    OutputSizes<DatatypeList...>();
}

int main()
{
    OutputSizes<char, int, long int>();
    return 0;
}

I'm using GNU GCC with -std=C++0x. Using -std=gnu++0x makes no difference.

Maxpm
  • 24,113
  • 33
  • 111
  • 170

2 Answers2

16

Here's how you disambiguate the base case:

#include <iostream>
#include <typeinfo>

template <typename FirstDatatype>
void OutputSizes()
{
    std::cout << typeid(FirstDatatype).name() << ": " << sizeof(FirstDatatype) << std::endl;
}

template <typename FirstDatatype, typename SecondDatatype, typename... DatatypeList>
void OutputSizes()
{
    OutputSizes<FirstDatatype>()
    OutputSizes<SecondDatatype, DatatypeList...>();
}

int main()
{
    OutputSizes<char, int, long int>();
}
Casey Rodarmor
  • 14,878
  • 5
  • 30
  • 33
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    I wonder if this is possible to make work without having a three-argument version of the template? – Omnifarious Feb 18 '11 at 00:52
  • The three argument OutputSizes should call the single argument one to reduce code duplication. – Omnifarious Feb 18 '11 at 01:02
  • Doug Gregor (the main force behind variadic templates) has recently submitted a core issue in this area. I am not knowledgable enough to know if it impacts or changes this use case or not (sorry). The issue has not yet been assigned a number so I can not point you to it. – Howard Hinnant Feb 18 '11 at 03:47
  • I thought at first that the second template could be ``, and that partial ordering would solve the ambiguity with the call to `OutputSizes`, but partial ordering won't be able to resolve that since there are no function parameters :( @Howard, did he post that issue to the core list somewhere? Note that this is not specific to variadic templates. For instance `template void f(); template void f();` and then a call to `f` is similarly ambiguous, I think. – Johannes Schaub - litb Feb 20 '11 at 17:06
1

It's because you didn't provide a base case. You extracted the last data type of the variadic template parameter- then you tried to match an empty variadic parameter to a function taking a type and a variadic parameter. You need to provide a "base case" for when the variadic parameter is empty.

using namespace std;

template <typename FirstDatatype, typename... DatatypeList>
void OutputSizes()
{
    std::cout << typeid(FirstDatatype).name() << ": " << sizeof(FirstDatatype) << std::endl;
    OutputSizes<DatatypeList...>();
}

template<typename... DataTypeList>
void OutputSizes() // We're called when there's no template arguments
                   // left in the pack
{
}

int main()
{
    OutputSizes<char, int, long int>();
    return 0;
}

Edit: The many-zero overloads I have shown here actually only work when you take actual run-time arguments too based on the template types. If you only take template parameters directly, you have use two-one recursion like shown in Howard Hinnant's answer.

Puppy
  • 144,682
  • 38
  • 256
  • 465