ความละเอียดเกินพิกัดเกิดขึ้นเฉพาะเมื่อ (a) คุณกำลังเรียกชื่อของฟังก์ชัน / โอเปอเรเตอร์หรือ (b) กำลังส่งไปยังตัวชี้ (ไปยังฟังก์ชันหรือฟังก์ชันสมาชิก) ด้วยลายเซ็นที่ชัดเจน
ไม่เกิดขึ้นที่นี่
std::function
ใช้วัตถุใด ๆ ที่เข้ากันได้กับลายเซ็นของมัน ไม่ใช้ตัวชี้ฟังก์ชันโดยเฉพาะ (แลมบ์ดาไม่ใช่ฟังก์ชั่นมาตรฐานและฟังก์ชั่นมาตรฐานไม่ใช่แลมบ์ดา)
ตอนนี้อยู่ในรูปแบบฟังก์ชัน homebrew ของฉันสำหรับลายเซ็นR(Args...)
ฉันก็ยอมรับR(*)(Args...)
อาร์กิวเมนต์ (การจับคู่แบบตรง) ด้วยเหตุผลนี้ แต่หมายความว่ายกระดับลายเซ็น "จับคู่แบบตรงทั้งหมด" ด้านบนลายเซ็น "ที่เข้ากันได้"
ปัญหาหลักคือชุดโอเวอร์โหลดไม่ใช่วัตถุ C ++ คุณสามารถตั้งชื่อชุดโอเวอร์โหลดได้ แต่คุณไม่สามารถผ่านมันไป "natively"
ตอนนี้คุณสามารถสร้างชุดหลอกของฟังก์ชันเช่นนี้:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
สิ่งนี้จะสร้างอ็อบเจกต์ C ++ เดียวที่สามารถทำการแก้ปัญหาโอเวอร์โหลดในชื่อฟังก์ชันได้
เราจะขยายมาโครให้มากขึ้น:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
ซึ่งน่ารำคาญที่จะเขียน เวอร์ชั่นที่เรียบง่ายมีประโยชน์น้อยกว่าอยู่ที่นี่:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
เรามีแลมบ์ดาที่รับการโต้แย้งจำนวนหนึ่งแล้วจึงส่งต่อให้สมบูรณ์ baz
สมบูรณ์
แล้ว:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
โรงงาน เราเลื่อนการแก้ปัญหาการโอเวอร์โหลดลงในแลมบ์ดาที่เราเก็บไว้fun
แทนที่จะส่งผ่านfun
การตั้งค่าโอเวอร์โหลดโดยตรง (ซึ่งไม่สามารถแก้ไขได้)
มีข้อเสนออย่างน้อยหนึ่งข้อในการกำหนดการดำเนินการในภาษา C ++ ที่แปลงชื่อฟังก์ชั่นเป็นวัตถุชุดเกินพิกัด จนกว่าข้อเสนอมาตรฐานดังกล่าวจะอยู่ในมาตรฐานOVERLOADS_OF
แมโครจะมีประโยชน์
คุณสามารถไปอีกขั้นหนึ่งและสนับสนุนการทำงานของตัวชี้แบบคาสต์
struct baz_overloads {
template<class...Ts>
auto operator()(Ts&&...ts)const
RETURNS( baz(std::forward<Ts>(ts)...) );
template<class R, class...Args>
using fptr = R(*)(Args...);
//TODO: SFINAE-friendly support
template<class R, class...Ts>
operator fptr<R,Ts...>() const {
return [](Ts...ts)->R { return baz(std::forward<Ts>(ts)...); };
}
};
แต่นั่นเริ่มที่จะได้รับป้าน
ตัวอย่างสด
#define OVERLOADS_T(...) \
struct { \
template<class...Ts> \
auto operator()(Ts&&...ts)const \
RETURNS( __VA_ARGS__(std::forward<Ts>(ts)...) ); \
\
template<class R, class...Args> \
using fptr = R(*)(Args...); \
\
template<class R, class...Ts> \
operator fptr<R,Ts...>() const { \
return [](Ts...ts)->R { return __VA_ARGS__(std::forward<Ts>(ts)...); }; \
} \
}