c++ - وظيفة القالب لا تعمل مع وظيفة تحويل المؤشر إلى المرجع




templates (2)

لقد كتبت مؤخرًا وظيفة قالب لحل بعض التكرارات البرمجية. تبدو هكذا:

template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr, const std::string& error, R (T::*fun)(Args...), Args... args) {
    if (auto sp = ptr.lock()) 
    {
        return std::invoke(fun, *sp, args...);
    }
    else 
    {
        throw std::runtime_error(error.c_str());
    }
}

int main() {
    auto a = std::make_shared<A>();
    call_or_throw(std::weak_ptr<A>(a), "err", &A::foo, 1);
}

هذا الرمز يعمل بشكل جيد للغاية class A التي تبدو كما يلي:

class A {
public:
    void foo(int x) {

    }
};

ولكن فشل في تجميع لأحد مثل هذا:

class A {
public:
    void foo(const int& x) {

    }
};

لماذا هو كذلك (لماذا أقصد سبب فشل استنتاج النوع) وكيف (إذا كان ذلك ممكنًا على الإطلاق) يمكنني جعل هذا الرمز يعمل مع المراجع؟ مثال حي


لا يمكن استنتاج أنواع Args على أنها const& (من إعلان المعلمة fun ) وغير مرجعية من إعلان args . إصلاح بسيط هو استخدام حزم معلمات نوع قالب منفصلة:

template<class T, class R, class... Args, class... DeclaredArgs>
R call_or_throw(
    const std::weak_ptr<T>& ptr,
    const std::string& error,
    R (T::*fun)(DeclaredArgs...),
    Args... args);

وكجانب سلبي ، يمكنني أن أتخيل رسائل خطأ أطول قليلاً في حالة الاستخدام السيئ.


لاحظ أن نوع معلمة القوالب Args يتم استخلاصها كـ const int& في وسيطة الوظيفة الثالثة &A::foo ، واستنتاجها كـ int على معلمة الدالة الرابعة 1 . أنها لا تتطابق وتسبب فشل الخصم.

يمكنك استبعاد المعلمة الرابعة من deduction ، على سبيل المثال

template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr, 
                const std::string& error, 
                R (T::*fun)(Args...), 
                std::type_identity_t<Args>... args) {
//              ^^^^^^^^^^^^^^^^^^^^^^^^^^                

LIVE

PS: std::type_identity معتمد منذ C ++ 20؛ ولكن من السهل جدا تنفيذ واحدة.





templates