繁体   English   中英

C++20 概念/需要表达式来测试泛型 lambda 是否接受类型

[英]C++20 concept / requires expression to test if generic lambda accepts type

我试图在编译时验证给定的 lambda 是否接受某种类型(在我的示例代码中为双倍)。 只要 lambda 的签名明确指定了它的工作类型。 但是,一旦我在签名中使用带有 auto 的通用 lambda,在评估 requires 语句时就会出现编译错误。

下面的代码片段说明了这个问题(也在编译器资源管理器上)

#include <concepts>
#include <iostream>
#include <string>

template<typename F>
concept accepts_double = requires(F f, double d) { f(d); };

struct Component{};

int main(){
    auto f1 = [](double a){double b = a;};
    auto f2 = [](std::string a){std::string b = a;};
    auto f3 = [](auto a){std::string b = a;};

    std::cout << std::boolalpha << accepts_double<decltype(f1)> << "\n"; // expected true
    std::cout << std::boolalpha << accepts_double<decltype(f2)> << "\n"; // expected false

//This one gives the error:
    std::cout << std::boolalpha << accepts_double<decltype(f3)> << "\n"; // expected false, gives compilation error
}

我的印象是,requires 语句会验证 f(d); 是一个有效的表达式,如果不是,则返回 false。 但是,在使用最新的 gcc 和 clang 进行编译时,我收到一条错误消息,表明它正在尝试评估函数体:

:13:38: error: no viable conversion from 'double' to 'std::string' (aka 'basic_string<char>')

我的问题是否有不同的方法来确保 lambda 可以传递双精度值,或者需要语句仅限于检查签名?

这是预期的行为。

lambda f3声称接受任何东西 但是为了测试它是否可以用double调用,我们需要实例化调用运算符。 只有该实例化的“直接上下文”中的失败才算作替换失败——其中直接上下文基本上是与实际函数签名密切相关的任何东西。 一旦我们进入调用运算符的主体,那将不再是直接上下文。 我们必须实例化主体,这会失败(无法从double构造string ),但这是一个硬编译器错误。

换句话说,这不是 SFINAE 友好的。


现在,需要实例化 lambda 的主体的唯一原因是它返回auto并且我们需要知道返回类型。 我们可以直接提供:

auto f3 = [](auto a) -> void {std::string b = a;};

在这里, accepts_double<decltype(f3)>编译。 但它给出了true 因为 lambda 确实声称接受一切。 这里完全没有限制。 由于我们碰巧不必实例化主体,我们才免于编译失败。

如果我们想确保这两者都能编译并给出正确的答案,我们需要添加该约束:

auto f3 = [](std::convertible_to<std::string> auto a) {std::string b = a;};

现在,我们实际上将参数限制为允许的类型集。 这既编译又正确地产生false (当然,因为double不能转换为std::string )。

暂无
暂无

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

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