Concept evaluability & Variable template partial specialization

Viewed 82

Currently, I am running into a problem that three major compilers are giving me three different results. (GCC trunk, Clang trunk, MSVC.v19.latest, all under x86-64).

The code & compiler settings are here on Compiler Explorer:
https://godbolt.org/z/WzqcxzEYc

#include <functional>
#include <concepts>
#include <limits>
#include <tuple>
#include <array>

template <typename... Tys>
struct _impl_AnySame;   // Undefined.

template <>
struct _impl_AnySame<> : std::false_type {};

template <typename T>
struct _impl_AnySame<T> : std::false_type {};

template <typename T, typename... Tys>
struct _impl_AnySame<T, Tys...>
{
    static constexpr bool value = std::disjunction_v<std::is_same<T, Tys>...> || _impl_AnySame<Tys...>::value;
};

template <typename T, typename... Tys>
concept AnySame = _impl_AnySame<T, Tys...>::value;

template<typename... Tys>
using tuple_cat_t = std::invoke_result_t<decltype(std::tuple_cat<Tys...>), Tys...>;

template<typename T, typename... Tys>
using Remove_t = tuple_cat_t<std::conditional_t<std::is_same_v<T, Tys>, std::tuple<>, std::tuple<Tys>>...>;

template <typename... Tys>
struct _impl_AnyOrder;  // Undefined.

template <>
struct _impl_AnyOrder<std::tuple<>, std::tuple<>> : public std::true_type {};

template <typename... Tys> requires(sizeof...(Tys) > 0)
struct _impl_AnyOrder<std::tuple<Tys...>, std::tuple<>> : public std::false_type {};

template <typename... Tys> requires(sizeof...(Tys) > 0)
struct _impl_AnyOrder<std::tuple<>, std::tuple<Tys...>> : public std::false_type {};

template <typename T1, typename... Tys1, typename... Tys2> requires(sizeof...(Tys2) > 0)
struct _impl_AnyOrder<std::tuple<T1, Tys1...>, std::tuple<Tys2...>>
{
    static constexpr bool value = AnySame<T1, Tys2...> && std::conjunction_v<_impl_AnyOrder<std::tuple<Tys1...>, Remove_t<T1, Tys2...>>>;
};

template <typename Tuple_t, typename... Tys>
concept AnyOrder = _impl_AnyOrder<Tuple_t, std::tuple<Tys...>>::value;

template<typename... Tys>
struct VariadicTemplateWrapper
{
    using Tuple_t = std::tuple<Tys...>;

    static constexpr std::size_t Count_v = sizeof...(Tys);
    
    template <typename... Tys2> static constexpr bool Isomer_v = AnyOrder<Tuple_t, Tys2...>;
    template <typename T> requires(requires{ typename T::Tuple_t; }) static constexpr bool Isomer_v<T> = _impl_AnyOrder<Tuple_t, typename T::Tuple_t>::value; // MSVC generate error from this line: "error C2131: expression did not evaluate to a constant"
    template <> static constexpr bool Isomer_v<> = Count_v == 0; // GCC generate errors from this line and the line above: "error: explicit template argument list not allowed"
};

#ifndef _MSVC_LANG
typedef char __int8;
typedef short __int16;
typedef int __int32;
typedef long long __int64;
#endif

int main(int argc, char** args) noexcept
{
    static_assert(AnySame<char, __int8, __int16, __int32, __int64>);
    static_assert(!AnySame<float, __int8, __int16, __int32, __int64>);

    static_assert(AnyOrder<std::tuple<int, float, double>, float, double, int>);
    static_assert(!AnyOrder<std::tuple<char, float, double>, float, double, bool>);
    static_assert(!AnyOrder<std::tuple<int, float>, float, double, int>);
    static_assert(!AnyOrder<std::tuple<int, float, double>, float, double>);

    using CharacterSet = VariadicTemplateWrapper<char, char8_t, wchar_t, char16_t, char32_t>;

    static_assert(CharacterSet::Isomer_v<char16_t, char32_t, char, wchar_t, char8_t>);
    static_assert(CharacterSet::Isomer_v<VariadicTemplateWrapper<char16_t, char32_t, char, wchar_t, char8_t>>);

    return EXIT_SUCCESS;
}

(I've put a comment next to the lines that cause errors.)

Clang considers my codes to be well-formed and executed as precisely what I intended;
GCC considers the problem my codes have is that I cannot have variable template specialized;
MSVC considers my codes to be ill-formed and the problem is that some part of my concept cannot be statically evaluated.

Which compiler is correct here, and how can I get it to work on all compilers?

0 Answers
Related