用成員函數重載實現is_convertible
C++標準庫中提供的可變參類模板std::is_convertible,這個類模板的主要能力是判斷能否從某個類型隱式地轉換到另一個類型,返回的是一個布爾值true或false。例如,一般的從int轉換成float或從float轉換成int,都是可以的。又如,有一個類A和一個類B,代碼如下。
class A
{
};class B : public A
{
};
因為類B的父類是類A,所以從類B轉換到類A是可以的,但從類A轉換到類B是不行的。
在main()主函數中加入幾行測試代碼:
#include "killCmake.h"#include<string>using namespace std;class A
{
};class B : public A
{
};int main()
{// std::is_convertible<X,Y> :是判斷能否從X類型轉到Y類型std::cout << std::is_convertible<float, int>::value << std::endl;std::cout << std::is_convertible<int, float>::value << std::endl;// 子類轉換到父類可以,但是父類不能轉換到子類,會截斷std::cout << std::is_convertible<A, B>::value << std::endl;std::cout << std::is_convertible<B, A>::value << std::endl;return 0;
}
從結果中可以看到,從類A轉換到類B是不允許的(結果為0),其他幾個轉換都是可以的(結果為1)。
在明白了std::is_convertible的功能后,現在就來深入了解一下它的實現源碼。這里,IsConvertibleHelper類模板和一個IsConvertible類模板,完成與std::is_convertible同樣的功能。這里尤其注意,不要把類型模板的參數搞反,第1個類型模板參數叫作FROM,第2個類型模板參數叫作TO。IsConvertibleHelper類模板實現的功能是測試從FROM類型轉換到TO類型是否可行。
template<typename From,typename To>
struct IsConvertibleHelper
{
private:static void testfunc(To);template<typename = decltype(testfunc(std::decltype<From>()))>static std::true_type test(void*);static std::false_type test(...);
public:using type = decltype(test(nullptr));
};
- 上面的代碼與以往講過的IsDefConstructibleHelper代碼非常類似,重載的test()成員函數返回類型分別是std::true_type和std::false_type。如果FROM類型能轉換成TO類型,那么就會匹配返回std::true_type的test()成員函數(成員函數模板);否則會匹配返回std::false_type的test成員函數。
- 值得注意的是,返回std::true_type的test()成員函數中類型模板參數默認值的寫法,看起來是用decltype推斷testfunc()成員函數的返回類型,傳遞給testfunc()的實參可以看作一個FROM類型的對象(std::declval()),如果FROM類型能被順利地轉換為TO類型,那么通過decltype推斷testfunc()的返回類型的寫法就是有效的(SFINAE原則),test()函數就會返回std::true_type,否則編輯器就會匹配返回類型為std::false_type的test()成員函數。
- 現在,繼續實現IsConvertible類模板,讓其繼承剛剛定義的IsConvertibleHelper模板中的type(type是一個類型,為std::true_type或std::false_type),代碼如下。
#include "killCmake.h"#include<string>using namespace std;class A
{
};class B : public A
{
};template<typename From,typename To>
struct IsConvertibleHelper
{
private:static void testfunc(To);template<typename = decltype(testfunc(std::decltype<From>()))>static std::true_type test(void*);static std::false_type test(...);
public:using type = decltype(test(nullptr));
};template<typename From,typename To>
struct IsConvertible : IsConvertibleHelper<From, To>::type // struct 默認的繼承方式是public繼承
{
};int main()
{// std::is_convertible<X,Y> :是判斷能否從X類型轉到Y類型std::cout << std::is_convertible<float, int>::value << std::endl;std::cout << std::is_convertible<int, float>::value << std::endl;// 子類轉換到父類可以,但是父類不能轉換到子類,會截斷std::cout << std::is_convertible<A, B>::value << std::endl;std::cout << std::is_convertible<B, A>::value << std::endl;return 0;
}
- 當FROM類型能夠轉換成TO類型時,IsConvertible的父類(IsConvertibleHelper<FROM, TO>::type)相當于std::true_type類型;當FROM類型不能轉換成TO類型時,IsConvertible的父類就相當于std::false_type類型。此時,std::true_type或std::false_type類型中的靜態成員變量value的值為true(1)或false(0)就代表FROM類型能否轉換為TO類型。
可以用一個變量模板簡化書寫:
#include "killCmake.h"#include<string>using namespace std;class A
{
};class B : public A
{
};template<typename From,typename To>
struct IsConvertibleHelper
{
private:static void testfunc(To);template<typename = decltype(testfunc(std::decltype<From>()))>static std::true_type test(void*);static std::false_type test(...);
public:using type = decltype(test(nullptr));
};template<typename From,typename To>
struct IsConvertible : IsConvertibleHelper<From, To>::type // struct 默認的繼承方式是public繼承
{
};template<typename From,typename To>
constexpr bool IsConvertible_v = IsConvertible<From, To>::value;int main()
{std::cout << IsConvertible_v<float, int> << std::endl;std::cout << IsConvertible_v<int, float> << std::endl;std::cout << IsConvertible_v<A, B> << std::endl;std::cout << IsConvertible_v<B, A> << std::endl;return 0;
}