Неоднозначная перегрузка на шаблонных вариационных шаблонах

Связанные с:


Рассмотрим эту пару вариационных шаблонов:

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, а второй - тот, который у вас не было.

Другие вопросы по тегам