std::conjunction and SFINAE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux