C++20概念/需要表达式来测试泛型lambda是否接受类型 [英] C++20 concept / requires expression to test if generic lambda accepts type

查看:19
本文介绍了C++20概念/需要表达式来测试泛型lambda是否接受类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在编译时验证给定的lambda是否接受某种类型(在我的示例代码中为Double)。只要lambda的签名明确指定了类型,它就可以工作。但是,只要我在签名中使用带有AUTO的泛型lambda,在计算Requires语句时就会出现编译错误。

以下代码片段说明了该问题(also on compiler explorer)

#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)> << "
"; // expected true
    std::cout << std::boolalpha << accepts_double<decltype(f2)> << "
"; // expected false

//This one gives the error:
    std::cout << std::boolalpha << accepts_double<decltype(f3)> << "
"; // 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传递双精度值,或者是否将Requires语句限制为仅检查签名?

推荐答案

这是预期行为。

lambdaf3声称接受任何。但是要测试它是否可以通过double调用,我们需要实例化调用操作符。只有该实例化的直接上下文中的失败才算作替换失败--其中直接上下文基本上是与实际函数签名密切相关的任何东西。一旦我们进入调用操作符的主体,这就不再是直接的上下文了。我们必须实例化Body,这会失败(无法从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)。

这篇关于C++20概念/需要表达式来测试泛型lambda是否接受类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆