Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSVC can't evaluate a constexpr function inside enable_if

Consider a simple utility function to calculate conjunction, along with a use this utility to ensure that types in a std::tuple are all equal.

#include <type_traits>
#include <tuple>

constexpr auto all() noexcept -> bool { return true; }

template <class... Bools>
constexpr auto all(bool const x, Bools... xs) noexcept -> bool
{
    return x && all(xs...);
}

template <class T, class = void>
struct foo;

template <class T, class... Ts>
struct foo< std::tuple<T, Ts...>
          , std::enable_if_t<all(std::is_same<T, Ts>::value...)>
          > {
};

int main()
{
    foo<std::tuple<int, int>> x;
}

GCC and Clang are fine with this code, but MSVC isn't. Here's a godbolt link. So I'm wondering, is this a MSVC bug or is it just me missing something?

like image 709
T. Westerhout Avatar asked Jul 07 '18 19:07

T. Westerhout


1 Answers

I would guess it is an MSVC bug. If C++17 is supported, I would suggest instead using std::conjunction. Under C++14, as a workaround, one can copy the "possible implementation" from the former link:

#include <type_traits>
#include <tuple>

template<class...> struct conjunction : std::true_type { };
template<class B1> struct conjunction<B1> : B1 { };
template<class B1, class... Bn>
struct conjunction<B1, Bn...> 
    : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
template<class... B>
constexpr bool conjunction_v = conjunction<B...>::value;

template <class T, class = void>
struct foo;

template <class T, class... Ts>
struct foo< typename std::tuple<T, Ts...>
        , std::enable_if_t<conjunction_v<std::is_same<T, Ts>...>>
        > {
};

int main()
{
    foo<std::tuple<int, int>> x;
}
like image 120
jcai Avatar answered Oct 11 '22 13:10

jcai