Hi, I was under the impression that you could use std::conjunction to avoid instantiating templates for arguments following an argument the ::value of which would evaluate to something equivalent to 'false'. The code below seems to be an example of when this is not the case. I'm I misunderstanding something or is there a bug somewhere in gcc or libstdc++? Best regards, /Johan Alfredsson To see the problem, try to compile the attached file code.cc as follows: bash> g++ -DFAIL -std=c++17 code.cc code.cc: In instantiation of ‘constexpr const bool is_barable_v<int>’: code.cc:12:90: required by substitution of ‘template<class T> using is_fooable_2 = std::enable_if_t<conjunction_v<has_baz<T, void>, std::integral_constant<bool, (! is_barable_v<T>)> > > [with T = int]’ code.cc:22:23: required by substitution of ‘template<class T, class> void func(const T&) [with T = int; <template-parameter-1-2> = <missing>]’ code.cc:27:21: required from here code.cc:10:38: error: ‘std::decay_t<int> {aka int}’ is not a class, struct, or union type template <typename T> constexpr bool is_barable_v = std::decay_t<T>::barable::value; ^~~~~~~~~~~~ Compiling without the -DFAIL works. The only difference is that is_barable<T> is inlined in this case.
#include <type_traits> template <typename T, typename = void> struct has_baz : std::false_type {}; template <typename T> struct has_baz<T, std::void_t<typename std::decay_t<T>::baz>> : std::true_type {}; template <typename T> using is_fooable_1 = std::enable_if_t<std::conjunction_v<has_baz<T>, std::bool_constant<!std::decay_t<T>::barable::value>>>; template <typename T> constexpr bool is_barable_v = std::decay_t<T>::barable::value; template <typename T> using is_fooable_2 = std::enable_if_t<std::conjunction_v<has_baz<T>, std::bool_constant<!is_barable_v<T>>>>; struct Foo { using barable = std::false_type; using baz = bool; }; void func(int) {} #ifdef FAIL // does not work template <typename T, typename = is_fooable_2<T>> void func(T const&) {} #else // works template <typename T, typename = is_fooable_1<T>> void func(T const&) {} #endif int main() { func(42); }