8

Can you use C++11 variadic templates to complete /* ??? */ in:

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

so that var_and<v...>::value provides && over the boolean pack v at compile-time?

Can you do the same for struct var_or<v...> for ||?

Can you use short-circuit evaluation (in both cases)?

Edit: An update to the accepted answer added that C++17 fold expressions enable

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

It seems that, for parameter pack-based approaches, only a restricted type of "short-circuit evaluation" is possible: while instantiating var_or<true,foo(),bar()> only calls || once, it also calls both foo and bar.

Community
  • 1
  • 1
nknight
  • 1,034
  • 8
  • 17
  • Smells like a homework assignment. – mah Aug 09 '12 at 22:19
  • 3
    @mah: I really doubt there exists any place teaching C++11 right now. – GManNickG Aug 09 '12 at 22:21
  • 1
    This is not homework. I am writing a zip iterator (Boost's is insufficient); this 'macro' is to determine whether all the component iterators have a certain property in common, based on boolean flags. I'm sure there's a cleaner way of doing it. – nknight Aug 09 '12 at 23:07
  • 1
    In that case, looks like a good problem to assign as homework ;) – mah Aug 10 '12 at 00:32

2 Answers2

11

You don't want value to be a 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;
};

Obviously the same can be done for ||.

Short circuit evaluation doesn't matter because this only deals with constant expressions which won't have any side effects.

Here's another method which stops recursively generating types as soon as it find a false value, emulating a kind of short circuiting:

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;
};

Update for C++17: Using a fold expression makes this much simpler.

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

Or also using a template variable as enobayram suggests:

template<bool... b> constexpr bool var_and = (b && ...);
bames53
  • 86,085
  • 15
  • 179
  • 244
  • Thanks for your answer, and correcting my error with the `typedef`... fixed in the question above. And I agree that short circuit evaluation doesn't matter; however, I'm still interested for purely academic reasons. Could you get this behavior by something like: `` and then `value = var_and

    ::value;`, plus I guess another base case? Do you think the compiler would exploit this?

    – nknight Aug 09 '12 at 23:18
  • 2
    Short circuiting will still be done insofar as the "compile-time evaluator" should never _evaluate_ the right side of `head && var_and::value` if the evaluation of the left side results in true. However the compiler still has to construct the expression, which means generating the type `var_and`. Since the calculation is done as part of constructing the type rather than as part of evaluating the `...::value` expression there is effectively no short circuiting with this method. However I think I know a way to get it. I'll edit my answer. – bames53 Aug 10 '12 at 00:14
  • I think you can spice the C++17 version further up by using an inline variable :) Less work for the compiler and it becomes a one-liner. – enobayram Aug 19 '16 at 05:24
4

I just needed something similar, but I have the luxury of using C++14, so I've ended up going with the following, which is probably faster (to compile) than the accepted answer:

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

Now, this is constexpr, so it can be used in compile time contexts as well as runtime. So we can, for instance, use it in a context like some_struct<and_all({true, false, arg_pack...})>

enobayram
  • 4,650
  • 23
  • 36
  • This answer improves on the (original) accepted answer by implementing short-circuiting, and goes beyond the posed question with a runtime consideration. Despite these improvements, I have not changed the accepted answer because _(1)_ my question explicitly concerned C++11, and _(2)_ the accepted answer was subsequently updated using (C++17) [fold expressions](http://en.cppreference.com/w/cpp/language/fold), like `template constexpr bool var_and = (... && b);`, exactly the construct I originally sought. – nknight Sep 19 '16 at 23:21
  • Sure, the accepted answer is more comprehensive, I just wanted to chip in my 2 cents. BTW, to be clear, this answer doesn't implement short-circuiting at the call site, that's a language-level feature that's available only in very specific circumstances. – enobayram Sep 20 '16 at 05:28
  • I think I'm still unclear -- could you elaborate further? The semantics of `and_all(bs)` appears identical to that of `bs[0] && /* ... */ && bs[N-1]`, so I would say the former "implements" the latter. – nknight Sep 20 '16 at 20:12
  • @nknight Maybe we understand different things from "short circuiting". I use it to imply the behavior, where `foo() && bar()` will never evaluate `bar()` if `foo()` returns `false`. But if you write `and_all(foo(), bar())`, both will be evaluated before being passed to `and_all`. – enobayram Sep 21 '16 at 05:51
  • Your understanding is the correct one; I now believe that none of the proposed solutions truly implement short circuiting. I have amended my original question with a comment meant to clarify this subtlety. – nknight Sep 27 '16 at 19:03