为什么这需要表达式作为一个概念而不是直接作用于函数?

Chr*_*s_F 1 c++ c++-concepts c++20 requires-expression

以下无法编译。

template <typename... U>
requires requires(U... x) { (std::to_string(x) && ...); }
auto to_string(const std::variant<U...>& value) {
    return std::visit([](auto&& value) {
        return std::to_string(std::forward<decltype(value)>(value));
    }, value);
}

int main() {
    std::variant<int, float> v = 42;
    std::cout << to_string(v) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/Wvn6E3PG5

如果我将直接的 require 表达式转换为一个概念,它就可以正常工作。

template<typename T, typename... U>
concept to_stringable = requires(U... u) { (std::to_string(u) && ...); };

template <to_stringable... U>
auto to_string(const std::variant<U...>& value) {
    return std::visit([](auto&& value) {
        return std::to_string(std::forward<decltype(value)>(value));
    }, value);
}

int main() {
    std::variant<int, float> v = 42;
    std::cout << to_string(v) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/W6znbvTzo

Art*_*yer 6

当你有:

template <to_stringable... U>
auto to_string(const std::variant<U0, U1>& value) {
Run Code Online (Sandbox Code Playgroud)

这会检查每个单独的类型是否满足to_stringable<T>,因此它本质上相当于:

template <to_stringable U0, to_stringable U1>
auto to_string(const std::variant<U0, U1>& value) {
Run Code Online (Sandbox Code Playgroud)

只需一个论点,T你的概念就是:

template <to_stringable U0, to_stringable U1>
auto to_string(const std::variant<U0, U1>& value) {
Run Code Online (Sandbox Code Playgroud)

然而,如果有多个参数,它看起来像:

requires(T t) { (std::to_string(t)); };
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为你不能&&两个std::strings,所以不满足约束。

你真正想做的是折叠一个约束:

requires(T1 t1, T2 t2) { (std::to_string(t1) && std::to_string(t2)); }
Run Code Online (Sandbox Code Playgroud)

...由于错误,哪个 gcc 似乎没有正确实现,但你可以逃脱:

template <typename... U>
requires ((requires(U x) { std::to_string(x); }) && ...)
Run Code Online (Sandbox Code Playgroud)