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) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
PS:
std::type_identity
معتمد منذ C ++ 20؛
ولكن من السهل جدا تنفيذ واحدة.