Ошибка компиляции в рекурсивной функции шаблона Variadic

Я подготовил простой тест шаблона с переменным числом аргументов в Code::Blocks, но получаю сообщение об ошибке:

Нет соответствующей функции для вызова 'OutputSizes()'

Вот мой исходный код:

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

Я использую GNU GCC с -std=C++0x. Использование -std=gnu++0x не имеет значения.


person Maxpm    schedule 17.02.2011    source источник


Ответы (2)


Вот как вы устраняете неоднозначность базового случая:

#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>();
}
person Howard Hinnant    schedule 17.02.2011
comment
Интересно, можно ли это заставить работать без версии шаблона с тремя аргументами? - person Omnifarious; 18.02.2011
comment
Выходные размеры с тремя аргументами должны вызывать единственный аргумент, чтобы уменьшить дублирование кода. - person Omnifarious; 18.02.2011
comment
Дуг Грегор (главная сила, стоящая за вариативными шаблонами) недавно представил основную проблему в этой области. Я недостаточно осведомлен, чтобы знать, влияет ли это на этот вариант использования или меняет его или нет (извините). Задаче еще не присвоен номер, поэтому я не могу указать вам на нее. - person Howard Hinnant; 18.02.2011
comment
Сначала я подумал, что вторым шаблоном может быть <typename FirstDatatype, typename... DatatypeList>, и что частичное упорядочение решит неоднозначность с вызовом OutputSizes<char>, но частичное упорядочение не сможет решить эту проблему, поскольку параметров функции нет :( @Howard, неужели он опубликовать эту проблему где-нибудь в основном списке? Обратите внимание, что это не относится к вариативным шаблонам. Например, template<typename T> void f(); template<typename T, typename U = void> void f();, а затем вызов f<int>, я думаю, также неоднозначен. - person Johannes Schaub - litb; 20.02.2011

Это потому, что вы не предоставили базовый вариант. Вы извлекли последний тип данных параметра шаблона с переменным числом аргументов, а затем попытались сопоставить пустой параметр с переменным числом аргументов с функцией, принимающей тип и параметр с переменным числом аргументов. Вам необходимо указать «базовый случай», когда параметр variadic пуст.

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

Редактировать: показанные здесь перегрузки со многими нулями на самом деле работают только тогда, когда вы также принимаете фактические аргументы времени выполнения на основе типов шаблонов. Если вы принимаете только параметры шаблона напрямую, вы используете рекурсию два-один, как показано в ответе Говарда Хиннанта.

person Puppy    schedule 17.02.2011
comment
Кажется, я понимаю, что вы имеете в виду, но не могли бы вы привести пример? Я попытался перегрузить его только template <typename Datatype>, но получил неоднозначные ошибки перегрузки. - person Maxpm; 18.02.2011
comment
@Maxpm: я не эксперт по шаблонам с переменным числом аргументов, поскольку мой компилятор их не поддерживает, но я считаю, что приведенное выше должно скомпилироваться. - person Puppy; 18.02.2011
comment
Я думаю, что использование термина «базовый класс» здесь сбивает с толку. Возможно, «условие завершения рекурсии» было бы лучше. - person Omnifarious; 18.02.2011
comment
Я не могу получить выше, чтобы скомпилировать. Не могли бы вы убедиться, что это работает? - person Casey Rodarmor; 24.02.2012
comment
Этот код не компилируется: неоднозначный вызов перегруженной функции. Пробовал с 3 разными компиляторами. - person Vladimir Reshetnikov; 04.03.2018