Неоднозначная перегрузка на шаблонных вариационных шаблонах
Связанные с:
- Неоднозначная перегрузка доступа к шаблонным функциям без аргументов с переменными параметрами
- Простая функция шаблона не может мгновенно
- Почему эта переменная функция неоднозначна?
Рассмотрим эту пару вариационных шаблонов:
template<typename Dummy>
bool All(Param& c) {
return true;
}
template<typename Dummy, Func* f, Func* ...rest>
bool All(Param& c) {
return f(c) && All<Dummy, rest...>(c);
}
Это работает и компилируется. Однако как написать это без первого параметра шаблона?
Звучит банально? Ну, это то, что я думал.:-) Давайте рассмотрим некоторые идеи.
Идея № 1:
template<Func* f, Func* ...rest>
bool All(Param& c) {
return f(c) && All<rest...>(c);
}
template<>
bool All(Param& c) {
return true;
}
Не сработает... Когда я пытался это сделать, я имел в виду специализацию, но со второй мысли это не так.
В исходном примере я создал два разных шаблона перегрузок, первый из которых принял 1 параметр шаблона, а второй - 2 или более. Никаких двусмысленностей и никакой специализации. я правильно понял?
Идея № 2:
bool All(Param& c) {
return true;
}
template<Func* f, Func* ...rest>
bool All(Param& c) {
return f(c) && All<rest...>(c);
}
Не будет работать, очевидно, All<rest...>
с rest...
пустота не будет расширяться до вызова не шаблонной функции.
Идея № 3:
Давайте немного перестроим решение.
template<Func* f>
bool All(Param& c) {
return f(c);
}
template<Func* f, Func* ...rest>
bool All(Param& c) {
return f(c) && All<rest...>(c);
}
Это не разрешено, потому что все (с) будут неоднозначными. Следовательно, мне нужно иметь случай 0-arg и случай>0-arg... Или как насчет случая 1-arg и случая>1-arg?
Идея № 3.5:
template<Func* f>
bool All(Param& c) {
return f(c);
}
template<Func* f, Func* f2, Func* ...rest>
bool All(Param& c) {
return f(c) && All<f2, rest...>(c);
}
Да, работает, но содержит copypasta (простой в данном случае, но может быть больше!), Поэтому я бы сказал, что это не лучше, чем я начал. Просто еще один обходной путь.
Идея № 4:
Давайте попробуем #1, но с классами вместо функций.
template<Func* f, Func* ...rest>
struct All {
static bool func(Param& c) {
return f(c) && All<rest...>(c);
}
};
template<>
struct All {
static bool func(Param& c) {
return true;
}
};
Это выглядит многообещающе, так как я могу специализироваться на занятиях. Но эй, что это?
извините, не реализовано: невозможно развернуть rest... в список аргументов фиксированной длины
Разве это не GCC 4.4? Я на MinGW GCC 4.6.1 (tdm-1).
В любом случае, я должен думать, что я не могу сделать такую элементарную вещь прямым способом? Требуется ли использовать обходной путь с дополнительным фиктивным параметром шаблона для выполнения этой задачи?
Или есть простой, правильный вариант, чтобы указать случай с нулевым аргументом, который будет работать?
2 ответа
В этом вопросе, поскольку параметры шаблона не являются типами, если мы подготовим функцию с аргументом шаблона по умолчанию, как показано ниже, Dummy
Параметр можно сохранить:
template<typename = void>
bool All(Param& c) {
return true;
}
template<Func* f, Func* ...rest>
bool All(Param& c) {
return f(c) && All<rest...>(c);
}
Однако я не уверен, что это всегда применимо. Для более общего случая, std::enable_if
или подобная отправка могла бы быть необходимой (это сделает код немного длинным все же).
Похоже, ваш вопрос похож на этот: Ошибка компиляции в функции рекурсивного вариационного шаблона
Там есть два ответа, которые должны работать; тот, который является вашим #3.5, а второй - тот, который у вас не было.