概念评估性&可变模板部分专业化
目前,我遇到了一个问题,三个主要编译器给我带来了三种不同的结果。 (gcc trunk,clang trunk,msvc.v19.latest,均在x86-64下)。
代码&编译器设置在编译器资源管理器上:
#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;
}
https://godbolt.org/z/wzqcccxzeyc 这会导致错误。)
clang认为我的代码是正确的,并且是我预期的;
海湾合作委员会认为我的代码遇到的问题是,我不能专门使用变量模板;
MSVC认为我的代码是错误的,问题在于我的概念>
的某些部分无法静态评估。
这里哪个编译器在这里是正确的,我该如何使其用于所有编译器?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论