Hi,

which of the 2 codes is correct:

 ``12345678910111213141516171819`` ``````template constexpr bool has() const { return tuple_helper::tuple_contains_type::value; } template constexpr bool has_every() const { if (has() && has()) { return true; } else { return has_every(); } } template constexpr bool has_every() const { return has(); }``````

 ``12345678910111213141516171819`` ``````template constexpr bool has() const { return tuple_helper::tuple_contains_type::value; } template constexpr bool has_every() const { if (has() && has() && has_every()) { return true; } else { return has_every(); } } template constexpr bool has_every() const { return has(); }``````

constraints_type is a tuple.
The intent is:

 `` `` ``for all Oi, has must be true for has_every to return true``

just pure logic

Regards,
Juan Dent
Both have problems with an even number of types. Consider this:
 ``1234567891011121314151617181920212223242526272829`` ``````template constexpr bool has() { return tuple_helper::tuple_contains_type::value; } struct Xx{}; template constexpr bool has_every() { return has(); // std::is_same::value } template constexpr bool has_every() { return has() && has() && has_every(); } int main() { struct X1{}; struct X2{}; struct X3{}; struct X4{}; has_every(); return 0; }``````
Or since 17:
 ``12345678910111213141516171819202122232425`` ``````template constexpr bool has() { return tuple_helper::tuple_contains_type::value; } template constexpr bool has_every() { if constexpr (sizeof...(Opts) > 0) return has() && has_every(); else return has(); } int main() { struct X1{}; struct X2{}; struct X3{}; struct X4{}; has_every(); return 0; }``````
Last edited on
Your solutions @coder777 also have problems with even number of types? Or are these your proposals for correct implementation?

Seems to me your C++17 solution is correct! not sure about the other one...
Last edited on
 Your solutions @coder777 also have problems with even number of types?
No, you can easily check that.

The first solution has the problem what to do with `Xx` (std::is_same<O1, Xx>::value as an hint).

When you havve 17 (you should) prever the second solution.
As a matter of fact your 17 solution IS correct; not the first code..
C++17
 ``12`` ``````template constexpr bool has_every() const noexcept { return (has() && ...); }``````

An implementation (as namespace scope functions) might look somewhat like this:
 ``12345678910`` ``````template struct tuple_contains; // could also inherit `std::conjunction` template struct tuple_contains, T> : std::bool_constant<(std::is_same_v || ...)> {}; template bool constexpr tuple_contains_v = tuple_contains(); template bool constexpr tuple_contains_all_v = (tuple_contains_v && ...); ``````
Last edited on
mbozzi wrote:
template <typename... Elts>
constexpr bool has_every() const noexcept { return (has<Elts>() && ...); }
What's the magic behind `(has<Elts>() && ...)`? Is the `&& ...` automatically removed when `...` contains nothing? Is `...` in this case a recursive call?

JUANDENT wrote:
not the first code..
That requires a bit more work...
It's a pack expansion called a fold expression. Specifically a unary right fold.

In general the compiler expands (has<Elts>() && ...) into
(has<Elts1>() && (has<Elts2>() && (... && (has<EltsN-1>() && has<EltsN>()))))

For example
- if Elts is the parameter pack containing A, B, C, D, then (has<Elts>() && ...) expands into
(has<A>() && (has<B>() && (has<C>() && has<D>())))
- If Elts is the parameter pack containing just one parameter A, then (has<Elts>() && ...) expands into (has<A>())
- If Elts is the empty parameter pack (has<Elts>() && ...) expands into true, a special case.

https://en.cppreference.com/w/cpp/language/fold
https://www.foonathan.net/2020/05/fold-tricks/
Last edited on
Okay, thank you for the explanation.