为什么std::visitinaunsatisfiedconcept会导致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);
};

该 lambda 可以使用vifv是 avariant或它继承自 one来调用。否则,它是错误的。这比通过visit.


以上是为什么std::visitinaunsatisfiedconcept会导致gcc编译错误的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>