[英]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.