С++ Variadic шаблон И и ИЛИ

Можете ли вы использовать вариативные шаблоны С++ 11 для завершения /* ??? */ в:

template<bool...v> struct var_and { static bool constexpr value = /* ??? */; };

чтобы var_and<v...>::value предоставлял && вместо логического пакета v во время компиляции?

Можете ли вы сделать то же самое для struct var_or<v...> для ||?

Можете ли вы использовать оценку короткого замыкания (в обоих случаях)?

Изменить: обновление принятого ответа добавило, что C++17 свернуть выражения включить

template<bool... v> constexpr bool var_and = (v && ...);
template<bool... v> constexpr bool var_or  = (v || ...);

Кажется, что для подходов, основанных на наборе параметров, возможен только ограниченный тип «краткой оценки»: хотя создание экземпляра var_or<true,foo(),bar()> вызывает || только один раз, он также вызывает как foo, так и bar.


person nknight    schedule 09.08.2012    source источник
comment
Пахнет домашним заданием.   -  person mah    schedule 10.08.2012
comment
@mah: Я действительно сомневаюсь, что сейчас есть место, где обучают C++11.   -  person GManNickG    schedule 10.08.2012
comment
Это не домашнее задание. Я пишу итератор zip (Boost недостаточно); этот «макрос» предназначен для определения того, имеют ли все итераторы компонентов определенное общее свойство на основе логических флагов. Я уверен, что есть более чистый способ сделать это.   -  person nknight    schedule 10.08.2012
comment
В таком случае, похоже, это хорошая задача для домашнего задания ;)   -  person mah    schedule 10.08.2012


Ответы (2)


Вы не хотите, чтобы value было typedef.

template<bool head, bool... tail>
struct var_and {
    static constexpr bool value = head && var_and<tail...>::value;
};

template<bool b> struct var_and<b> {
    static constexpr bool value = b;
};

Очевидно, то же самое можно сделать и для ||.

Оценка короткого замыкания не имеет значения, потому что она имеет дело только с константными выражениями, которые не будут иметь никаких побочных эффектов.

Вот еще один метод, который останавливает рекурсивную генерацию типов, как только находит ложное значение, эмулируя своего рода короткое замыкание:

template<bool head, bool... tail>
struct var_and { static constexpr bool value = false; };

template<bool... tail> struct var_and<true,tail...> {
    static constexpr bool value = var_and<tail...>::value;
};

template<> struct var_and<true> {
    static constexpr bool value = true;
};

Обновление для C++17: использование выражения fold делает это намного проще.

template<bool...v> struct var_and {
    static constexpr bool value = (v && ...);
};

Или также использовать переменную шаблона, как предлагает enobayram:

template<bool... b> constexpr bool var_and = (b && ...);
person bames53    schedule 09.08.2012
comment
Спасибо за ваш ответ и исправление моей ошибки с typedef..., исправленной в вопросе выше. И я согласен, что оценка короткого замыкания не имеет значения; тем не менее, я все еще заинтересован по чисто академическим причинам. Не могли бы вы получить такое поведение с помощью чего-то вроде: <bool h1, bool h2, bool...tail>, а затем value = var_and<h1 && h2, tail...>::value;, плюс, я думаю, еще один базовый случай? Как вы думаете, компилятор воспользуется этим? - person nknight; 10.08.2012
comment
Короткое замыкание по-прежнему будет выполняться, поскольку оценщик времени компиляции никогда не должен оценивать правую часть head && var_and<tail...>::value, если оценка левой стороны дает true. Однако компилятор все еще должен построить выражение, что означает создание типа var_and<tail...>. Поскольку вычисление выполняется как часть построения типа, а не как часть оценки выражения ...::value, в этом методе фактически нет короткого замыкания. Однако я думаю, что знаю способ получить его. Я отредактирую свой ответ. - person bames53; 10.08.2012
comment
Я думаю, что вы можете еще больше оживить версию C++17, используя встроенную переменную :) Меньше работы для компилятора, и он становится однострочным. - person enobayram; 19.08.2016

Мне просто нужно было что-то подобное, но я могу позволить себе роскошь использовать С++ 14, поэтому в итоге я выбрал следующее, что, вероятно, быстрее (для компиляции), чем принятый ответ:

template <size_t N>
constexpr bool and_all(const bool (&bs) [N]) {
  for(bool b: bs) if(!b) return false;
  return true;
}

Теперь это constexpr, поэтому его можно использовать как в контексте времени компиляции, так и во время выполнения. Так что мы можем, например, использовать его в таком контексте, как some_struct<and_all({true, false, arg_pack...})>

person enobayram    schedule 18.08.2016
comment
Этот ответ улучшает (исходный) принятый ответ за счет реализации короткого замыкания и выходит за рамки поставленного вопроса с учетом времени выполнения. Несмотря на эти улучшения, я не изменил принятый ответ, потому что (1) мой вопрос явно касался C++11, и (2) принятый ответ был впоследствии обновлен с использованием ( C++17) выражения сворачивания, такие как template<bool... b> constexpr bool var_and = (... && b);, в точности та конструкция, которую я изначально искал. - person nknight; 20.09.2016
comment
Конечно, принятый ответ является более полным, я просто хотел внести свои 2 цента. Кстати, чтобы было ясно, этот ответ не реализует короткое замыкание на месте вызова, это функция на уровне языка, доступная только в очень определенных обстоятельствах. - person enobayram; 20.09.2016
comment
Я думаю, что я все еще неясен - не могли бы вы уточнить? Семантика and_all(bs) кажется идентичной семантике bs[0] && /* ... */ && bs[N-1], поэтому я бы сказал, что первый реализует второй. - person nknight; 20.09.2016
comment
@nknight Может быть, мы понимаем разные вещи от короткого замыкания. Я использую его, чтобы обозначить поведение, при котором foo() && bar() никогда не будет оценивать bar(), если foo() возвращает false. Но если вы напишете and_all(foo(), bar()), оба будут оценены перед передачей в and_all. - person enobayram; 21.09.2016
comment
Ваше понимание правильное; Теперь я считаю, что ни одно из предложенных решений не реализует короткое замыкание. Я исправил свой первоначальный вопрос комментарием, призванным прояснить эту тонкость. - person nknight; 27.09.2016