Sẽ không dễ dàng hơn khi triển khai phiên bản không hoạt động quá tải in (void)?
Ahh well. Các mẫu chức năng và quá tải sẽ dễ dàng xử lý điều này khi chạy.
Sẽ hơi phức tạp nếu bạn muốn xử lý điều này lúc biên dịch, để sử dụng với #if macro hoặc xác nhận thời gian biên dịch tĩnh.
Nhưng kể từ khi bạn chỉ muốn trước đây, tôi có thể đề nghị một cái gì đó như thế này như là một điểm khởi đầu:.
(Tested dưới (GCC) 3.4.4 & 4.0.1 - Tôi biết, tôi cần phải nâng cấp !)
#include <iostream>
using namespace std;
struct Foo {
void operator()() {}
};
struct Bar {
bool operator()() { return false; }
};
Foo foo;
Bar bar;
bool baz() { return false; }
void bang() {}
struct IsVoid
{
typedef char YES[1];
typedef char NO[2];
/* Testing functions for void return value. */
template <typename T>
static IsVoid::NO & testFunction(T (*f)());
static IsVoid::YES & testFunction(void (*f)());
static IsVoid::NO & testFunction(...);
/* Testing Objects for "void operator()()" void return value. */
template <typename C, void (C::*)()>
struct hasOperatorMethodStruct { };
template <typename C>
static YES & testMethod(hasOperatorMethodStruct<C, &C::operator()> *);
template <typename C>
static NO & testMethod(...);
/* Function object method to call to perform test. */
template <typename T>
bool operator() (T & t)
{
return ( (sizeof(IsVoid::testFunction(t)) == sizeof(IsVoid::YES))
|| (sizeof(IsVoid::testMethod<T>(0)) == sizeof(IsVoid::YES)));
}
};
#define BOUT(X) cout << # X " = " << boolToString(X) << endl;
const char * boolToString(int theBool)
{
switch (theBool)
{
case true: return "true";
case false: return "false";
default: return "unknownvalue";
}
}
int main()
{
IsVoid i;
BOUT(IsVoid()(foo));
BOUT(IsVoid()(bar));
BOUT(IsVoid()(baz));
BOUT(IsVoid()(bang));
cout << endl;
BOUT(i(foo));
BOUT(i(bar));
BOUT(i(baz));
BOUT(i(bang));
}
Được rồi, tôi bắt đầu để xem chi tiết của vấn đề.
Trong khi chúng ta có thể làm điều gì đó dọc theo dòng này:
#include <iostream>
using namespace std;
struct FooA {
void operator()() {}
};
struct FooB {
bool operator()() { return false; }
};
struct FooC {
int operator()() { return 17; }
};
struct FooD {
double operator()() { return 3.14159; }
};
FooA fooA;
FooB fooB;
FooC fooC;
FooD fooD;
void barA() {}
bool barB() { return false; }
int barC() { return 17; }
double barD() { return 3.14159; }
namespace N
{
/* Functions */
template <typename R>
R run(R (*f)()) { return (*f)(); }
bool run(void (*f)()) { (*f)(); return true; }
/* Methods */
template <typename T, typename R>
R run(T & t, R (T::*f)()) { return (t .* f)(); }
template <typename T>
bool run(T & t, void (T::*f)()) { (t .* f)(); return true; }
};
#define SHOW(X) cout << # X " = " << (X) << endl;
#define BOUT(X) cout << # X " = " << boolToString(X) << endl;
const char * boolToString(int theBool)
{
switch (theBool)
{
case true: return "true";
case false: return "false";
default: return "unknownvalue";
}
}
int main()
{
SHOW(N::run(barA));
BOUT(N::run(barA));
SHOW(N::run(barB));
BOUT(N::run(barB));
SHOW(N::run(barC));
SHOW(N::run(barD));
cout << endl;
SHOW(N::run(fooA,&FooA::operator()));
BOUT(N::run(fooA,&FooA::operator()));
SHOW(N::run(fooB,&FooB::operator()));
BOUT(N::run(fooB,&FooB::operator()));
SHOW(N::run(fooC,&FooC::operator()));
SHOW(N::run(fooD,&FooD::operator()));
}
Bạn làm vẫn có mà cần pha vào bóng ăn & CLASS :: operator() trong như một cuộc tranh cãi.
Cuối cùng, trong khi chúng ta có thể xác định xem hành của đối tượng() phương thức trả về một khoảng trống, chúng ta có thể không bình thường quá tải dựa trên các loại trở lại.
Chúng tôi có thể vượt qua giới hạn quá tải đó thông qua chuyên môn mẫu. Nhưng sau đó chúng tôi nhận được vào sự xấu xí này trong đó chúng tôi vẫn cần phải xác định các loại ... Đặc biệt là loại trả lại! Hoặc là thủ công hoặc bằng cách chuyển vào một đối số phù hợp để từ đó chúng tôi có thể trích xuất các loại cần thiết.
BTW: #define macro cũng không giúp ích gì. Các công cụ như thế nào?: Yêu cầu cùng loại cho cả hai? và: một phần.
Vì vậy, đây là tốt nhất tôi có thể làm ...
Dĩ nhiên ...
Nếu bạn không cần kiểu trả về ...
Nếu bạn chỉ chuyển kết quả cho một chức năng khác ...
Bạn có thể làm một việc như sau:
#include <iostream>
using namespace std;
struct FooA {
void operator()() {}
};
struct FooB {
bool operator()() { return false; }
};
struct FooC {
int operator()() { return 17; }
};
struct FooD {
double operator()() { return 3.14159; }
};
FooA fooA;
FooB fooB;
FooC fooC;
FooD fooD;
void barA() {}
bool barB() { return false; }
int barC() { return 17; }
double barD() { return 3.14159; }
#define SHOW(X) cout << # X " = " << (X) << endl;
namespace N
{
template <typename T, typename R>
R run(T & t, R (T::*f)()) { return (t .* f)(); }
template <typename T>
bool run(T & t, void (T::*f)()) { (t .* f)(); return true; }
template <typename T>
void R(T & t)
{
SHOW(N::run(t, &T::operator()));
}
template <typename T>
void R(T (*f)())
{
SHOW((*f)());
}
void R(void (*f)())
{
(*f)();
SHOW(true);
}
};
int main()
{
N::R(barA);
N::R(barB);
N::R(barC);
N::R(barD);
N::R(fooA);
N::R(fooB);
N::R(fooC);
N::R(fooD);
}
Thử nghiệm nó và nó hoạt động trên gcc 4.2.1. –
"Bản in" chỉ là để trình diễn những gì đang xảy ra ... những gì tôi đang làm là gói các phương thức và chức năng để chuyển sang cơ chế gọi lại asynch của người khác. Hầu hết các hàm và hàm của tôi trả về void - đôi khi tôi cần có khả năng trả về boolean cho cuộc gọi lại không đồng bộ của bên thứ ba. –
Điều này rất trơn! Không có một hoặc hai nhưng ba thủ thuật tôi đã không nhận được đúng - một là hai trường hợp NO trong quá tải của testFunction, một trong những hasOperatorMethodStruct fiddle, và một là cách kết hợp hai điều kiện! Rất giáo dục, tôi nợ bạn một thức uống giải khát của sự lựa chọn của bạn. –