You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++概念可求值性与变量模板偏特化多编译器兼容问题

C++多编译器编译结果不一致问题

在x86-64平台下使用GCC trunk、Clang trunk、MSVC v19.latest三款主流C编译器编译同一段C代码时,三款编译器给出了完全不同的编译结果。触发错误的代码行已在下方完整代码中添加注释标注:

#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;
}
三款编译器的具体行为
  • Clang:判定代码为良构,编译通过后运行结果完全符合代码设计预期
  • GCC:编译报错,提示类内不允许编写带显式模板参数列表的变量模板特化,报错起始位置为上述代码中两个Isomer_v的定义行
  • MSVC:编译报错,提示代码中部分concept表达式无法求值为常量,判定代码为非法格式,报错起始位置为带requires约束的Isomer_v重载行
待解答问题
  1. 上述三款编译器的行为中,哪一款符合C++标准规范要求?
  2. 如何修改代码,可实现GCC、Clang、MSVC三大编译器的全兼容?

内容的提问来源于stack exchange,提问作者Hydrogen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 22:36:20