繁体   English   中英

为什么std::visit in a unsatisfied concept会导致gcc编译错误

[英]Why does std::visit in an unsatisfied concept cause a compile error in gcc

这段代码:

#include <concepts>
#include <string>
#include <variant>

struct any_callable {
public:
    template<typename T>
    void operator()(T&&) {}
};

template<typename V>
concept is_variant = requires(V v) { std::visit(any_callable{}, v); };

int main() {
    constexpr bool wrapped = is_variant<std::string>;
}

不能在 gcc 11 下编译。它给出了一堆关于valueless_by_exception等的错误。 但是,它确实在 msvc ( Godbolt ) 下编译。 现在,据我所知,在这种情况下,如果它通常无法编译,它将衰减为 false,否则为 true。 msvc 的行为似乎支持这一点。

所以:这是 gcc 中的错误,msvc 的非标准功能,和/或我的代码有错吗?

那个:

template<typename V>
concept is_variant = requires(V v) { std::visit(any_callable{}, v); };

完全有效是最近的变化,这是P2162的结果。 为了使此检查工作,您需要std::visit成为通常所说的“SFINAE-friendly”。 也就是说:它必须以某种方式被限制在“变体”上,这样如果V是变体,它就可以工作,如果V不是变体,那么visit从重载集中删除,这样这个调用就是一个无效的表达式(以便可以拒绝该concept )。

但是,在 P2162 之前, std::visit没有约束 这不是 SFINAE 友好的:调用要么有效,要么格式错误。 正是这篇论文添加了一个约束,即您传递给它的类型是变体(或从一个变体)。 这就是为什么您会看到您所看到的错误: visit调用失败,但不是以对concept检查友好的方式。

在 P2162 之后(正如论文所指出的,MSVC 已经实现,但 libstdc++ 没有实现),您的支票将有效。

但是我们可以在 C++20 中更容易地做到这一点,而无需进入变体机制 - 通过以与论文相同的方式直接检查变体性:

template<typename V>
concept is_variant = requires(V v) {
    []<typename... Ts>(std::variant<Ts...> const&){}(v);
};

如果v是一个variant或者它继承自一个variant ,那么该 lambda 可以用v调用。 否则,它是错误的。 这比通过visit更直接。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM