c++ - 导致 msvc 和 clang 中编译器错误的概念?

标签 c++ visual-c++ clang c++20 c++-concepts

我有以下代码:

#include <variant>

template <typename T>
struct S{};

using Var = std::variant<S<int>, S<float>>;

template <typename T>
concept VariantMember = requires(Var var) { std::get<T>(var); };

void foo(VariantMember auto x) {}
void foo(auto x) {}

void bar()
{
    foo(S<int>{});
    foo(S<char>{});
}

MSVC 错误

error C2338: get(variant<Types...>&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)

只有当我在本例中的变体 S 中使用同一模板的两个实例时,才会发生这种情况。因此,首先 std::get 意外出错,然后这个概念并没有失败,而是直接出错。有趣的是,如果我在概念之外使用 std::get ,例如:

std::get<S<int>>(Var{ S<int>{} });

代码编译良好。

Clang 似乎忽略了这个概念,并且在这两种情况下总是选择 foo 的第一个重载。

godbolt

这些实际上是错误还是我搞砸了?

最佳答案

首先,你的S模板是噪音。删除它。

using Var = std::variant<int, float>;

template <typename T>
concept VariantMember = requires(Var var) { std::get<T>(var); };

template <int = 1>
void foo(VariantMember auto x) {}

template <int = 2>
void foo(auto x) {}

void bar()
{
    foo(int{});
    foo(char{});
}

我们得到了同样的错误。如果我注释掉 char在这种情况下,它在 MSVC 中编译得很好。

std::get<char>(Var{})不需要对 SFINAE 友好。 std::get在这里,MSVC 可能(并且确实)出现硬故障。

在此版本中,clang 和 msvc 都调用 int=1一旦我删除 char 就会过载一个正在犯硬错误的人。

我们如何处理硬错误?写一个get事实并非如此; safe_get :

template<class T, class...Ts>
requires (1 == (std::is_same_v<T, Ts>+...))
T& safe_get( std::variant<Ts...>& var ) 
  return std::get<T>(var);
}
template<class T, class...Ts>
requires (1 == (std::is_same_v<T, Ts>+...))
T const& safe_get( std::variant<Ts...> const& var ) 
  return std::get<T>(var);
}
// ...
template <typename T>
concept VariantMember = requires(Var var) {
  {safe_get<T>(var)};
};

(我添加并声明 1,这给了我“匹配且仅一次”)。

然后我们返回您的 S模板和everything works .

关于c++ - 导致 msvc 和 clang 中编译器错误的概念?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67470470/

相关文章:

python - 如何配置环境以使用 LLVM Clang 构建 python 嵌入式 c 代码

c++ - std::shared_ptr 线程安全

c++ - 我什么时候应该在现代 C++ 中使用(非头文件)源文件?

c++ - header 多重重新定义

c++ - 在 ARM 上初始化 uint32x4_t 时出现错误 C2078?

c++ - 为什么 std::thread 在其构造函数中等待?

C++ typedef 修复模板参数

visual-c++ - 将 GNU asm 调用转换为 VC++

c - 是否有描述 Clang 如何处理多余浮点精度的文档?

ios - 为什么我会看到有关使用 LLVM 的 -falign-loops 的编译错误?