请求从 lambda 转换为非标量类型

Conversion from lambda to non-scalar type requested

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

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(); }
};

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

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

但是当我尝试这样做时:

Value<double> f = []() { return 1.; };

触发编译错误:

error: conversion from 'main()::<lambda()>' to non-scalar type 'Value<double>' requested

你可以试试这个例子here

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

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

lambda 不是 std::function。这意味着当你做

Value<double> f = []() { return 1.; };

您需要将 []() { return 1.; } 转换为 std::function,这是用户定义的转换,然后您需要将 std::function 转换为 Value<double>,这是另一个用户定义的转换。当您最多只允许一次这样的转换时,这是两个用户定义的转换。这就是代码编译失败的原因。

Why does assigning work for T and not std::function<T()> and how can I make it so it does?

你的代码没有使用赋值,但是copy initialization

In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.

所以要让它工作,你必须让你的 ctor 直接接受 lambda(这是简化的例子):

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

live code You probably want to add restriction using std::enable_if or concept if C++20 is allowed to this ctor as well as in this form this constructor would try to accept everithing other overloads would not and may produce cryptic errrors. And according to this 它可以像

一样简单
template<class Y, typename = decltype(std::declval<Y&>()())>
Value(Y lambda ) : get( std::move( lambda ) )  {}

支持C++14。这是 yet another live example ,您可以在其中看到此构造函数未用于类型 int:

的初始化程序
 Value<double> d2 = 123;

prog.cpp:9:5: note: candidate template ignored: substitution failure [with Y = int]: called object type 'int' is not a function or function pointer Value(Y lambda ) : get( std::move( lambda ) ) {}