爲了檢測如果一個類具有特定名稱的方法或成員變量,可以用經典的SFINAE的方法:
template<typename T>
class has_x {
private:
typedef char yes[1];
typedef char no[2];
template<typename U> static yes& test_member(decltype(U::x));
template<typename U> static no& test_member(...);
template<typename U, U> struct check;
template<typename U> static yes& test_method(check<float (U::*)(), &U::x>*);
template<typename U> static no& test_method(...);
public:
static const bool as_method = (sizeof(test_method<T>(0)) == sizeof(yes));
static const bool as_member = (sizeof(test_member<T>(0)) == sizeof(yes));
};
其可以在微小的測試套件進行測試:
struct something_else {
};
struct fn_vec {
float x() const { return 66; };
};
struct mem_vec {
mem_vec() : x(55) {};
float x;
};
int main(int argc, char*argv[]) {
std::cout << "fv: " << has_x<fn_vec>::as_method << std::endl;
std::cout << "mv: " << has_x<mem_vec>::as_method << std::endl;
std::cout << "se: " << has_x<something_else>::as_method << std::endl;
std::cout << std::endl;
std::cout << "fv: " << has_x<fn_vec>::as_member << std::endl;
std::cout << "mv: " << has_x<mem_vec>::as_member << std::endl;
std::cout << "se: " << has_x<something_else>::as_member << std::endl;
return 0;
}
,輸出:
fv: 1
mv: 0
se: 0
fv: 0
mv: 1
se: 0
可以再用使用編寫特定於每種類型的函數或結構的變體。您也可以使用logical operators in std::enable_if
's condition來創建任何您需要的條件組合。
在同一個測試框架是一個愚蠢的例子如上:
template<typename T>
typename std::enable_if<has_x<T>::as_method, float>::type getX(const T& v) {
return v.x();
}
template<typename T>
typename std::enable_if<has_x<T>::as_member, float>::type getX(const T& v) {
return v.x;
}
template<typename T>
void foo(const T& val) {
std::cout << getX(val) << std::endl;
}
int main(int argc, char*argv[]) {
fn_vec fn;
mem_vec mem;
foo(fn);
foo(mem);
return 0;
}
,輸出:
66
55
這應該希望給你你需要創建通用框架,所有的工具。因爲所有東西都是模板化的,所以它的大部分都應該通過編譯器進行優化,最終達到合理的效率。
所有在Linux上的GCC 4.8.2測試過,但它應該在任何C++ 11編譯器中工作。
我不確定,但我認爲這樣可以爲您節省施工操作,因爲您並未構建臨時設備。 – pikeyboom 2015-10-21 13:49:14