请求从 lambda 到非标量类型的转换

cab*_*nto 4 c++ lambda templates std-function

我创建了这个类,这样我就可以拥有任何类型的值,该值要么是固定的,要么是在每次使用时重新计算:

template<typename T>
class Value {
    private:
    bool fixed;
    union {
        T value;
        std::function<T()> get;
    };
    public:
    Value(const T& value) : fixed(true), value(value) {}
    Value(const std::function<T()>& get) : fixed(false), get(get) {}
    Value(const T *pointer) : Value([pointer]() { return *pointer; }) {}
    ~Value() {}
    operator T() { return fixed ? value : get(); }
};
Run Code Online (Sandbox Code Playgroud)

以下所有表达式似乎都可以正常工作:

Value<double> a = 2.2;
double b = 1.;
double c = a;
Value<double> d = &b;
Value<int> e = Value<int>([]() { return 1.; });
Run Code Online (Sandbox Code Playgroud)

但是当我尝试这样做时:

Value<double> f = []() { return 1.; };
Run Code Online (Sandbox Code Playgroud)

触发编译错误:

error: conversion from 'main()::<lambda()>' to non-scalar type 'Value<double>' requested
Run Code Online (Sandbox Code Playgroud)

您可以在这里尝试这个示例。

为什么分配有效T而不std::function<T()>有效?我怎样才能做到这一点?

注意:我知道这个答案,但我不清楚如何解决这个问题,而不必像我那样显式调用构造函数Value<double> e

Sla*_*ica 5

为什么分配适用于 T 而不是 std::function<T()> 以及如何才能做到这一点?

您的代码不使用赋值,而是复制初始化

此外,复制初始化中的隐式转换必须直接从初始化器生成 T,而直接初始化则期望从初始化器到 T 构造函数的参数进行隐式转换。

因此,要使其工作,您必须让您的 ctor 直接接受 lambda (这是简化的示例):

template<typename T>
class Value {
    std::function<T()> get;    
public:
    
    template<class Y>
    Value(Y lambda ) : get( std::move( lambda ) )  {}
};
Run Code Online (Sandbox Code Playgroud)

实时代码如果此构造函数允许使用 C++20,则您可能希望添加限制使用std::enable_if或概念,并且在此形式中此构造函数将尝试接受其他重载不会接受的所有内容,并且可能会产生神秘的错误。根据这个enable_if模板参数是lambda(带有特定签名)它可以像

template<class Y, typename = decltype(std::declval<Y&>()())>
Value(Y lambda ) : get( std::move( lambda ) )  {}
Run Code Online (Sandbox Code Playgroud)

支持C++14。这是另一个实例,您可以看到此构造函数不用于类型的初始值设定项int

 Value<double> d2 = 123;
Run Code Online (Sandbox Code Playgroud)

prog.cpp:9:5: 注意:候选模板被忽略:替换失败 [Y = int]:被调用的对象类型“int”不是函数或函数指针 Value(Y lambda ) : get( std::move( lambda ) ) {}

  • 这是应用此答案+enable_if约束的原始示例:http://coliru.stacked-crooked.com/a/91ef3d3829cd423d (2认同)