要实现is_abstract,需要思考abstract类的特性:
- 无法实例化,也无法定义类对象数组
- 借助模板特化进行类型匹配
- 需要借助元编程(需要在编译时确定结果)
- 借助SFINAE让模板推导能够正确
1、数组类型参数和模板函数的匹配
注意,数组与指针的类型是不一样的!
#include <iostream>
#include <type_traits>
using namespace std;
template<class T>
void test(T(*)[1]){//可以匹配二维数组,优先级低于 void test(A(*)[1])
cout << "test template\n";
}
void test(A(*)[1]){//可以匹配二维数组
cout << "test A[][]\n";
}
void test(A**){//无法匹配二维数组
cout << "test A**\n";
}
void test(...){//万能匹配
cout << "test....\n";
}
int main(){
A arr[2][1];
test(arr);
return 0;
}
这里匹配优先级自行归纳!通过代码我们可以了解数组是能够进行精确匹配的,也就是能够实现函数重载或者叫模板特化!
2、元编程+SFINAE实现
这里借助模板类来实现元编程,返回static constexpr作为元数据,该数据必须在编译时确定!
#include <iostream>
using namespace std;
namespace master{
template<class T>
struct is_abstract
{
using yes = char[1];
using no = char[2];
template<class U>
static no& reallyAbstract(U(*)[2]);//精确匹配
template<class U>
static yes& reallyAbstract(...);//万能匹配
//sizeof 也是编译期操作符,所以能够在编译时进行计算
static constexpr bool value = (sizeof(reallyAbstract<T>(0)) == sizeof(yes));
};
}
class A{
};
class B{
virtual void print() = 0;
};
int main(){
cout << "is_abstract A = " << master::is_abstract<A>::value << endl;
cout << "is_abstract B = " << master::is_abstract<B>::value << endl;
return 0;
}