为什么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.
THE END
二维码