Это, вероятно, будет очень простое объяснение, но я собираюсь дать как можно больше предыстории, если я ошибаюсь. Продвинутые извинения за то, что вы так многословны. Я использую gcc4.5, и я понимаю, что поддержка С++ 0x по-прежнему несколько экспериментальна, но я буду действовать исходя из предположения, что существует причина, связанная с ошибкой, которую я вижу.
Я экспериментирую с шаблонами вариационной функции. Конечная цель состояла в том, чтобы создать cons-list из std::pair
. Он не должен был быть обычным типом, а просто строкой парных объектов. Функция, которая строит список, должна быть в некотором роде рекурсивной, причем конечное возвращаемое значение зависит от результата рекурсивных вызовов. В качестве добавленного твиста, последовательные параметры складываются вместе, прежде чем вставляться в список. Поэтому, если я прохожу [1, 2, 3, 4, 5, 6], конечный результат должен быть {1 + 2, {3 + 4, 5 + 6}}.
Моя первоначальная попытка была довольно наивной. Функция, Build, с двумя перегрузками. Один взял два идентичных параметра и просто вернул их сумму. Другой принял два параметра и пакет параметров. Возвращаемое значение представляло собой пару, состоящую из суммы двух заданных параметров и рекурсивного вызова. Оглядываясь назад, это была явно некорректная стратегия, потому что функция не объявляется, когда я пытаюсь выяснить ее тип возврата, поэтому у нее нет выбора, кроме как разрешить нерекурсивную версию.
Это я понимаю. Там, где я запутался, была вторая итерация. Я решил сделать эти функции статическими членами класса шаблона. Вызываемые функции не параметризуются, а весь класс. Мое предположение заключалось в том, что когда рекурсивная функция пытается сгенерировать свой возвращаемый тип, она создаст новую версию структуры со своей собственной статической функцией, и все будет работать.
В результате получилось: "error: нет соответствующей функции для вызова BuildStruct<double, double, char, char>::Go(const char&, const char&)
"
Код нарушения:
static auto Go(const Type& t0, const Type& t1, const Types&... rest)
-> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))>
Моя путаница возникает из-за того, что параметры BuildStruct
всегда должны быть теми же типами, что и аргументы, отправленные на BuildStruct::Go
, но в коде ошибки Go отсутствуют начальные два двойных параметра. Что мне здесь не хватает? Если мое первоначальное предположение о том, как статические функции будут выбраны, было неправильным, почему он пытается вызвать неправильную функцию, а не просто не найти какую-либо функцию вообще? Кажется, это просто смешение типов волей-неволей, и я просто не могу объяснить, почему. Если я добавлю дополнительные параметры к первоначальному вызову, он всегда будет стремиться к этому последнему шагу перед сбоем, поэтому, по-видимому, сама рекурсия по крайней мере частично работает. Это прямо контрастирует с первоначальной попыткой, которая всегда не сразу находила вызов функции.
В конечном счете, я преодолел проблему, с довольно элегантным решением, которое вряд ли похоже на одну из первых двух попыток. Поэтому я знаю, как делать то, что хочу. Я ищу объяснение неудачи, которую я видел.
Полный код, который следует соблюдать, поскольку я уверен, что моего словесного описания недостаточно. Сначала какой-нибудь шаблон, если вы хотите выполнить код и увидеть его сами. Затем начальная попытка, которая не удалась разумно, затем вторая попытка, которой не было.
#include <iostream>
using std::cout;
using std::endl;
#include <utility>
template<typename T1, typename T2>
std::ostream& operator <<(std::ostream& str, const std::pair<T1, T2>& p) {
return str << "[" << p.first << ", " << p.second << "]";
}
//Insert code here
int main() {
Execute(5, 6, 4.3, 2.2, 'c', 'd');
Execute(5, 6, 4.3, 2.2);
Execute(5, 6);
return 0;
}
Неструктурное решение:
template<typename Type>
Type BuildFunction(const Type& t0, const Type& t1) {
return t0 + t1;
}
template<typename Type, typename... Rest>
auto BuildFunction(const Type& t0, const Type& t1, const Rest&... rest)
-> std::pair<Type, decltype(BuildFunction(rest...))> {
return std::pair<Type, decltype(BuildFunction(rest...))>
(t0 + t1, BuildFunction(rest...));
}
template<typename... Types>
void Execute(const Types&... t) {
cout << BuildFunction(t...) << endl;
}
Результирующие ошибки:
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]':
test.cpp:33:35: instantiated from here
test.cpp:28:3: error: no matching function for call to 'BuildFunction(const int&, const int&, const double&, const double&, const char&, const char&)'
Решение структуры:
template<typename... Types>
struct BuildStruct;
template<typename Type>
struct BuildStruct<Type, Type> {
static Type Go(const Type& t0, const Type& t1) { return t0 + t1; }
};
template<typename Type, typename... Types>
struct BuildStruct<Type, Type, Types...> {
static auto Go(const Type& t0, const Type& t1, const Types&... rest)
-> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> {
return std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))>
(t0 + t1, BuildStruct<Types...>::Go(rest...));
}
};
template<typename... Types>
void Execute(const Types&... t) {
cout << BuildStruct<Types...>::Go(t...) << endl;
}
Результирующие ошибки:
test.cpp: In instantiation of 'BuildStruct<int, int, double, double, char, char>':
test.cpp:33:3: instantiated from 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]'
test.cpp:38:41: instantiated from here
test.cpp:24:15: error: no matching function for call to 'BuildStruct<double, double, char, char>::Go(const char&, const char&)'
test.cpp:24:15: note: candidate is: static std::pair<Type, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...))> BuildStruct<Type, Type, Types ...>::Go(const Type&, const Type&, const Types& ...) [with Type = double, Types = {char, char}, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...)) = char]
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]':
test.cpp:38:41: instantiated from here
test.cpp:33:3: error: 'Go' is not a member of 'BuildStruct<int, int, double, double, char, char>'