Lambda'dan skaler olmayan türe dönüştürme talep edildi

Dec 08 2020

Bu sınıfı, her kullanıldığında sabit veya yeniden hesaplanan her türden bir değere sahip olabilmek için oluşturdum:

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

Aşağıdaki tüm ifadeler iyi çalışıyor gibi görünüyor:

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

Ama yapmaya çalıştığımda:

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

bir derleme hatası tetiklendi:

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

Bu örneği buradan deneyebilirsiniz .

Atama neden işe yarıyor, işe yaramıyor Tve bunu std::function<T()>nasıl yapabilirim?

Not: Bu cevabın farkındayım, ancak yaptığım gibi yapıcıyı açıkça aramak zorunda kalmadan sorunu nasıl çözeceğimi bana netleştirmedim Value<double> e.

Yanıtlar

4 Slava Dec 08 2020 at 00:22

Std :: function <T ()> yerine T için iş atamak neden işe yarıyor ve bunu nasıl yapabilirim?

Kodunuz atama kullanmaz, ancak kopyalama başlatma ve

Ek olarak, kopya başlatmadaki örtük dönüştürme T'yi doğrudan başlatıcıdan üretmelidir, örneğin, doğrudan başlatma, başlatıcıdan T'nin yapıcısının bir argümanına örtük bir dönüşüm bekler.

Bu yüzden çalışmasını sağlamak için ctor'unuzun lambda'yı doğrudan kabul etmesini sağlamalısınız (bu basitleştirilmiş bir örnektir):

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

Canlı kod Muhtemelen kullanarak kısıtlamayı eklemek istediğiniz std::enable_ifC ++ 20 ve şifreli Errrors üretebilir olmaz diğer aşırı yükleri everithing kabul etmeye çalışacağını bu yapıcı bu ctor yanı sıra bu formda izin verildiği takdirde veya kavramı. Ve bu enable_if şablon parametresine göre lambda (belirli bir imzayla) şu kadar basit olabilirdi:

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

C ++ 14'ü destekler. İşte bu kurucunun tür başlatıcısı için kullanılmadığını görebileceğiniz başka bir canlı örnekint :

 Value<double> d2 = 123;

prog.cpp: 9: 5: not: aday şablon yok sayıldı: ikame hatası [Y = int ile]: çağrılan nesne türü 'int' bir işlev veya işlev işaretçisi değil Değer (Y lambda): get (std :: move (lambda )) {}

4 NathanOliver Dec 08 2020 at 00:17

Lambda, a değildir std::function. Bu yaptığın zaman demektir

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

dönüştürmek için gereken []() { return 1.; }bir içine std::functionbir kullanıcı tanımlı dönüşüm olan ve daha sonra bunu dönüştürmek için gereken std::functionbir içine Value<double>başka bir kullanıcı tanımlı bir dönüşüm olan. Bu, yalnızca böyle bir dönüşüme kadar izin verildiğinde kullanıcı tanımlı iki dönüşümdür. Kodun derlenememesinin nedeni budur.