В следующем определении функции шаблона я дважды напишу относительно длинное выражение details::transform(std::forward<T>(t)), где t - пакет параметров.

Как я могу это учитывать?

auto pack = details::transform(std::forward<T>(t)) конечно не работает.

template<class ...T>
void f(T&&... t)
{
    auto check = (details::transform(std::forward<T>(t)) && ...);
    if (check == false) {
        return;
    }
    details::act(details::transform(std::forward<T>(t))...);
}

Для целей тестирования здесь представлена полная программа для coliru.

3
YSC 21 Авг 2018 в 16:13

3 ответа

Лучший ответ

В C ++ есть печальная правда. Пересылка может стать кластером токенов. И чем сложнее выражение, которому нужно что-то передать, тем более болезненным оно может стать.

К сожалению, единственный способ, которым я знаю, чтобы смягчить это, это с препроцессором ...

#define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)

Имея это в виду, мы можем реорганизовать вашу функцию, чтобы использовать IILE для генерации этого пакета только один раз:

template<class ...T>
void f(T&&... t)
{
    [](auto&&... pack) {
        auto check = (FWD(pack) && ...);
        if (check == false) {
            return;
        }
        details::act(FWD(pack)...);
    }(details::transform(FWD(t))...);
}

Таким образом, вы вызываете transform только один раз для аргумента. Я предполагаю, что это чистая цель. В противном случае вы можете использовать препроцессор для генерации чего-то более простого без лямбды.

4
StoryTeller - Unslander Monica 21 Авг 2018 в 13:48

Вы не можете сделать это. Ваши два вариационных выражения расширяются до разных шаблонов. Лучшее, что вы можете сделать, это что-то вроде этого (без макросов):

template<class ...T>
void f(T&&... t)
{
    using details::transform;
    // (T&&)t == std::forward<T>(t);

    auto check = (transform((T&&)t) && ...);
    if (check == false) {
        return;
    }
    details::act(transform((T&&)t)...);
}
1
Rakete1111 21 Авг 2018 в 13:28

Вы могли бы использовать макрос.

#define FORWARD_TRANSFORM(type, var) details::transform(std::forward<type>(var))

Тогда ваша функция становится

template<class ...T>
void f(T&&... t)
{
    auto check = (FORWARD_TRANSFORM(T, t) && ...);
    if (check == false) {
        return;
    }
    details::act(FORWARD_TRANSFORM(T, t)...);
}
4
NathanOliver 21 Авг 2018 в 13:23
51949542