Информация об изменениях

Сообщение Re[5]: Помогите с вариадиками от 09.01.2018 18:14

Изменено 09.01.2018 18:22 watchmaker

Re[5]: Помогите с вариадиками
Здравствуйте, SaZ, Вы писали:

SaZ> А можете пояснить про typename T = void и почему это помогло?


Это не самая важная часть: можно и без этого.
Указания параметра по умолчанию =void используется просто чтобы задать условие окончания через специализацию (а она для функций возможна только полная).

Чаще, конечно, окончание рекурсии делается через подсчёт параметров и ту же перегрузку. Но тут у тебя все функции имеют ровно один и тот же список аргументов (const Table& table), и для них этот способ закрыт.

Хотя можно это обойти, если ввести в сигнатуру функции эти типы, добавив, например, фиктивный аргумент.
Тогда у всех функций будут разные сигнатуры и перегрузка будет работать:
bool ValidateTuple(const Table& table, std::tuple<>*) {
    return false;
}

template <typename Head, typename ...Tail>
bool ValidateTuple(const Table& table, std::tuple<Head*, Tail*...>*) 
{
    if (Validate_1<Head>(table))
      return true;
    return ValidateTuple(table, static_cast<std::tuple<Tail*...>*>(nullptr));
}

template <typename ...Tables> 
bool Validate(const Table& table) {
    return ValidateTuple(table, static_cast<std::tuple<Tables*...>*>(nullptr));
}

Тут просто передаётся нулевой указатель (оптимизатор его выбросит потом) на кортеж, параметры которого и являются тем списком классов, который осталось проверить.
Re[5]: Помогите с вариадиками
Здравствуйте, SaZ, Вы писали:

SaZ> А можете пояснить про typename T = void и почему это помогло?


Это не самая важная часть: можно и без этого.
Указания параметра по умолчанию =void используется просто чтобы задать условие окончания через специализацию (а она для функций возможна только полная).

Чаще, конечно, окончание рекурсии делается через подсчёт параметров и ту же перегрузку. Но тут у тебя все функции имеют ровно один и тот же список аргументов (const Table& table), и для них этот способ закрыт.

Хотя можно это обойти, если ввести в сигнатуру функции эти типы, добавив, например, фиктивный аргумент.
Тогда у всех функций будут разные сигнатуры и перегрузка будет работать:
bool ValidateTuple(const Table& table, std::tuple<>*) {
    return false;
}

template <typename Head, typename ...Tail>
bool ValidateTuple(const Table& table, std::tuple<Head*, Tail*...>*) 
{
    if (Validate_1<Head>(table))
      return true;
    return ValidateTuple(table, static_cast<std::tuple<Tail*...>*>(nullptr));
}

template <typename ...Tables> 
bool Validate(const Table& table) {
    return ValidateTuple(table, static_cast<std::tuple<Tables*...>*>(nullptr));
}

Тут просто передаётся нулевой указатель (оптимизатор его выбросит потом) на кортеж, параметры которого и являются тем списком классов, который осталось проверить.

Upd: Этот код — просто демонстрация, я не говорю, что так нужно писать :)