การอ่านคำถามที่เกี่ยวข้อง "วิธีโทรหาสมาชิก ทำงานเฉพาะในกรณีที่วัตถุมีมันหรือไม่" และ "เป็นไปได้ไหมที่จะเขียนเทมเพลต C++ เพื่อตรวจสอบการมีอยู่ของฟังก์ชัน" ฉันกำลังใช้คลาสคุณลักษณะของตัวเอง วัตถุประสงค์นั้นง่ายมาก แม้ว่าฉันไม่สามารถบรรลุสิ่งที่ฉันต้องการได้: จัดเตรียมคลาสลักษณะที่เปลี่ยนเส้นทางการเรียกไปยังคลาสที่ตรงกันแบบคงที่
ดังนั้น หากคลาสที่ฉันระบุให้กับคุณลักษณะของฉันมี เช่น วิธีการ void open_file()
มันก็เรียกมัน มิฉะนั้น ให้ใช้ฟังก์ชันคุณลักษณะ (a NOP
หนึ่ง แต่ตอนนี้เป็นเอาต์พุต) แน่นอนว่านี่เป็นงานของ SFINAE แต่เนื่องจากไม่คุ้นเคยกับกระบวนการนี้มากนัก ฉันจึงได้ปฏิบัติตามแนวคิดต่างๆ ดังที่คุณจะเห็น
ทุกอย่างทำงานได้ดีสำหรับ void open_file()
แต่เมื่อลอง void open_file(int)
มันกลับไม่ตรงกันและเรียกใช้ฟังก์ชัน NOP
นี่คือความพยายามของฉัน (เกือบจะเป็นคำต่อคำจากคำถามสองข้อนั้น!):
template <class Type>
class my_traits
{
//! Implements a type for "true"
typedef struct { char value; } true_class;
//! Implements a type for "false"
typedef struct { char value[2]; } false_class;
//! This handy macro generates actual SFINAE class members for checking event callbacks
#define MAKE_MEMBER(X) \
public: \
template <class T> \
static true_class has_##X(decltype(&T::X)); \
\
template <class T> \
static false_class has_##X(...); \
public: \
static constexpr bool call_##X = sizeof(has_##X<Type>(0)) == sizeof(true_class);
MAKE_MEMBER(open_file)
public:
/* SFINAE foo-has-correct-sig :) */
template<class A, class Buffer>
static std::true_type test(void (A::*)(int) const)
{
return std::true_type();
}
/* SFINAE foo-exists :) */
template <class A>
static decltype(test(&A::open_file)) test(decltype(&A::open_file), void *)
{
/* foo exists. What about sig? */
typedef decltype(test(&A::open_file)) return_type;
return return_type();
}
/* SFINAE game over :( */
template<class A>
static std::false_type test(...)
{
return std::false_type();
}
/* This will be either `std::true_type` or `std::false_type` */
typedef decltype(test<Type>(0, 0)) type;
static const bool value = type::value; /* Which is it? */
/* `eval(T const &,std::true_type)`
delegates to `T::foo()` when `type` == `std::true_type`
*/
static void eval(Type const & t, std::true_type)
{
t.open_file();
}
/* `eval(...)` is a no-op for otherwise unmatched arguments */
static void eval(...)
{
// This output for demo purposes. Delete
std::cout << "open_file() not called" << std::endl;
}
/* `eval(T const & t)` delegates to :-
- `eval(t,type()` when `type` == `std::true_type`
- `eval(...)` otherwise
*/
static void eval(Type const &t)
{
eval(t, type());
}
};
class does_match
{
public:
void open_file(int i) const { std::cout << "MATCHES!" << std::endl; };
};
class doesnt_match
{
public:
void open_file() const { std::cout << "DOESN'T!" << std::endl; };
};
อย่างที่คุณเห็นฉันได้ใช้ทั้งสองอย่าง อันแรกที่มีมาโคร MAKE_MEMBER
เพียงตรวจสอบการมีอยู่ของสมาชิก และมันใช้งานได้ ต่อไป ฉันพยายามใช้สำหรับ SFINAE if/else
แบบคงที่ เช่น หากมีฟังก์ชันสมาชิกอยู่แล้วให้เรียกมัน มิฉะนั้น ให้ใช้ฟังก์ชันที่กำหนดไว้ล่วงหน้า โดยไม่ประสบความสำเร็จ (อย่างที่ฉันบอก ฉันไม่ได้ลึกเกินไป เข้าสู่ SFINAE)
ความพยายามครั้งที่สองเกือบจะเป็นคำต่อคำจากคำถาม ตรวจสอบลายเซ็นและการมีอยู่ แต่ฉันได้แก้ไขเพื่อจัดการพารามิเตอร์ อย่างไรก็ตาม มันจะไม่ทำงาน:
does_match it_does;
doesnt_match it_doesnt;
my_traits<decltype(it_does)>::eval(it_does);
my_traits<decltype(it_doesnt)>::eval(it_doesnt);
// OUTPUT:
// open_file() not called
// open_file() not called
แน่นอนว่ามีปัญหาเกิดขึ้นที่นี่ ฉันไม่ได้ระบุพารามิเตอร์ แต่ฉันไม่รู้ว่าจะทำอย่างไร
ฉันกำลังพยายามทำความเข้าใจและเรียนรู้ นอกจากนี้ ฉันสามารถใช้ open_file()
ที่ขึ้นอยู่กับพารามิเตอร์เทมเพลต เช่น การจับคู่ SFINAE template <class T> open_file(T t)
ได้หรือไม่
ขอบคุณและไชโย!