غير قادر على إنشاء قوالب الوظائف التي تستخدم Decltype لاستنتاج نوع الإرجاع ، إذا تم استدعاؤها من داخل Lambda؟
-
22-09-2019 - |
سؤال
أحاول استخدام C ++ 0x ، وخاصة تعبير Lambda وإلغاء تبسيط بعض التعليمات البرمجية الخاصة بي ، باستخدام برنامج التحويل البرمجي MSVC10 RC.
لقد واجهت مشكلة غريبة للغاية:
template <typename F>
auto foo(F f) -> decltype(f()){
return f();
}
template <typename F>
void bar(F f){
f();
}
int main() {
bar([](){
foo([]() { }); // error C2893: Failed to specialize function template ''unknown-type' foo(F)'
});
}
كما هو موضح في التعليق ، يقوم المترجم بإنشاء خطأ على السطر foo([]() { })
.
أكره أن أصرخ "Bug Pres" ، لكنني حقًا لا أستطيع رؤية أي تفسير جيد لهذا الخطأ. على ما يبدو ، بينما داخل تعبير Lambda الخارجي ، لا يمكن للمترجم تخصص foo
قالب وظيفة لامبادا الداخلية.
ومع ذلك ، إذا كان تعريف foo
تم تغييره إلى Hardcode نوع الإرجاع ، مثل هذا:
template <typename F>
void foo(F f){
return f();
}
ثم كل شيء يجمع على ما يرام.
هل هناك بعض الغموض الغامضة للإعلان عند استخدامها لاستنتاج نوع إرجاع معلمات تعبير Lambda داخل نطاق Lambda آخر لست على علم به؟
المحلول
هذه مجرد بعض حالات الاختبار للناس لمراقبة.
يعمل
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
void dummy() {}
int main()
{
auto x = []()
{ // non-lambda parameter
foo(dummy);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto f = [](){};
auto x = [&]()
{ // pre-defined lambda
foo(f);
};
}
فشل
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda
foo([]{});
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda
auto f = []{};
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda, explicit return
// (explicit return type fails too, `-> void`)
auto f = [](){ return; };
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda, explicit return non-void
// (explicit return type fails too, `-> int`)
foo([]{ return 5; });
};
}
لذلك يبدو أن الأمر يتعلق بالنطاق و ال (?)void
نوع lambda الداخلية ، حتى عندما يكون صريحا.
نصائح أخرى
طبيعة "Auto" هي السماح للمترجم بحساب النوع. ولكن مثالك الأول يحتوي على مراجع متكررة على بعضها البعض ، لذا لحساب Auto's لـ Foo ، تحتاج إلى شريط وإنشاء مثيل للشريط الذي تحتاجه إلى FOO.
من ناحية أخرى ، يقول المثال الثاني بشكل صريح عن المترجم: "يجب أن يكون مؤشرًا للعمل ، لذا تهدأ لبعض الوقت". نظرًا لأن المؤشر إلى الوظيفة محسوبة جيدًا ، يعرف برنامج التحويل البرمجي نوعًا ما هو محجوز بالضبط. فقط للتناظرية: قارن إعلان الأعضاء إلى الأمام
struct A; //forward
...
A a1; //this is an error
A *a2; //this is correct since pointer calculated in bytes