类,有公共的可访问的内嵌类;
多态:允许使用不同的参数类型的性质就是多态,字面上即“多种形式的能力”;
在C++中,多态有两种:静态多态,即编译期多态;动态多态,即运行期多态;
编译期多态使得我们可以在编译期做出选择,而这正是我们所向往追求的。
Boost的type traits library:这是MPL的基石
以下代码抽自boost/或自己的替代实现,知其然,知其所以然,我们后面使用到的时候才可以了然于胸
1. primary type
is_xxx系列的metafunction具有成员value,而且我们只关心成员value的值为true/false
template< bool x > struct bool_

...{
static bool const value = x;
typedef bool_<x> type;
typedef bool value_type;

operator bool() const ...{ return x; }
};
typedef bool_<false> false_;
typedef bool_<true> true_;

is_xxx系列派生自bool_,下面逐一给出is_xxx的实现
is_integral通过对integral类型进行特化达到
template<typename type>

struct is_integral : false_...{}; // 即默认所有类型均不是integral类型

// at this moment, variadic template still has nothing to do with this condition
template<bool arg0, bool arg1, bool arg2=false, bool arg3=false, bool arg4=false, bool arg5=false, bool arg6=false, bool arg7=false, bool arg8=false, bool arg9=false>
struct ice_or

...{
static const bool value = arg0+arg1+arg2+arg3+arg4+arg5+arg6+arg7+arg8+arg9;
};

template<bool arg0, bool arg1, bool arg2=true, bool arg3=true, bool arg4=true, bool arg5=true, bool arg6=true, bool arg7=true, bool arg8=true, bool arg9=true>
struct ice_and

...{
static const bool value = arg0*arg1*arg2*arg3*arg4*arg5*arg6*arg7*arg8*arg9;
};
// 然后对可枚举的integral类型进行特化,其中还有对应的const/volatile/const volatile版本

template<> struct is_integral<char>: true_......{};

template<> struct is_integral<const char>: true_......{};

template<> struct is_integral<volatile char>: true_......{};

template<> struct is_integral<const volatile char>: true_......{};
C++中的integral类型有以下:
bool / char / unsigned char / signed char / wchar_t / short / unsigned short / int / unsigned int / long / unsigned long / long long / unsigned long long
分别对以上类型进行特化,我们就可以得到完整的is_integral
is_float的实现跟is_integral相同,c++中,float类型只有float/double/long double,还有对应的const/volatile/const volatile版本;
template<typename type>

struct is_void : false_...{};

template<> struct is_void<void> : true_...{};

template<> struct is_void<const void> : true_...{};

template<> struct is_void<const volatile void> : true_...{};
Is_function使用variadic template实现,否则需要根据函数的参数个数一一进行特化,很麻烦,c++0x直接支持variadic template, conceptgcc已经实现了variadic template功能
template<typename type>

struct is_function : false_...{};
template<typename retType, typename ... argType>

struct is_function<retType (*)(argType...)> : true_...{};
template<typename type>

struct is_member_function : false_...{};
template<typename retType, typename classType, typename ... argType>

struct is_member_function<retType (classType::*)(argType...)> : true_...{};

template<typename type> struct is_array : false_......{};

template<typename type, int N> struct is_array<type[N]> : true_......{};

template<typename type> struct is_array<type[]> : true_......{};
// 然后是对应的const/volatile/const volatile版本true_{};
is_member_pointer的实现类似于is_function,其中,is_member_pointer分为两种:1,类成员数据指针;2,类成员函数指针
template<typename type>

struct is_member_pointer :false_...{};
template<typename dataType, typename classType>

struct is_member_pointer<dataType classType::*> : true_...{};
template<typename retType, typename classType, … argType>

struct is_member_pointer<retype (classType::*)(argType…)> : true_...{};
//还有对应的const/volatile/const volatile版本
template<typename type>

struct is_pointer : false_...{};
template<typename type>

struct is_ponter<type*> : true_...{};
template<typename type>

struct is_pointer : is_function<type>...{};
template<typename type>

struct is_pointer : is_member_pointer<type>...{};

template<typename type>

struct is_reference : false_...{};
template<typename type>

struct is_reference<type&> : true_...{};
// 还有对应的const/volatile/const volatile版本

C++中的类类型包括:class/struct/union定义的类型,对于类类型,可以定义其类成员指针,包括成员数据指针及成员函数指针,boost就是利用这个性质来区分是否为类类型
template<typename type> char class_helper(int type::*);
template<typename type> int class_helper(...);

template<typename type>
struct is_class_helper

...{
static const bool value = sizeof(class_helper<type>(0))==sizeof(char) ? true : false;
};

template<typename type>

struct is_class : bool_<is_class_helper<type>::value>...{};

现在,剩下is_union/is_enum未实现,这几个比较麻烦,需要编译器提供相当的支持,boost提供保守的支持,就是将is_union/is_enum都默认为false_。
2. secondary type
template<typename type>

struct is_arithmetic : boos_...<ice_or<is_integral<type>::value, is_float<type>::value>::value>{};
is_fundamental的实现:包含算术类型和void类型
template<typename type>

struct is_fundamental: bool_...<ice_or<is_arithmetic<type>::value, is_void<type>::value>::value>{};
根据C++标准,复合类型包括数组/函数/指针/引用/类类型/枚举/成员指针,或者说,除了基础类型,其它的都是复合类型,而基础类型则只包括算术类型和void类型。
template<typename type>

struct is_compound: bool_<!is_fundamental<type>::value>...{};

在C++中,对象是指除了函数和引用之外的所有东西
template<typename type>

struct is_object: bool_<!ice_or<is_function<type>::value, is_reference<type>::value>::value>{};
根据C++定义,标量类型包括算术类型/枚举类型/指针类型
template<typename type>

struct is_scalar: bool_<ice_or<is_arithmetic<type>::value, is_pointer<type>::value, is_member_pointer<type>::value>::value>{};

枚举类型需要编译器的支持,boost中保守地将其置为false_。
3. type property
alignment_of用于编译期计算出类型的对齐长度,alginment_of还需要对void进行特化
template<typename type>

struct alignment_of_helper...{
char c;
type t;
};
template<typename type>

struct alignment_of...{
static const int value = (sizeof(alignment_of_helper)-sizeof(c))<size(type)?(sizeof(alignment_of_helper)-sizeof(c)):sizeof(type);
};


is_empty
template<typename type>

struct is_empty_helper : type...{};
template<typename type, bool isClass=false>
struct is_empty_helper1

...{
static const bool value = false;
};
template<typename type>
struct is_empty_helper1<type,true>

...{
static const bool value = (sizeof(is_empty_helper<type>) == sizeof(type));
};
template<typename type>

struct is_empty : bool_<is_empty_helper1<type, is_class<type>::value>...{};
如果类类型是多态的,即类具有虚函数
template<typename Type, bool isClass=false>
struct is_polymorphic_helper

...{
static const bool value = false;
};

template<typename Type>
struct is_polymorphic_helper<Type,true>

...{
typedef typename remove_cv<Type>::type ncvType;

struct base1 : ncvType...{~base1()...{}};

struct base2 : ncvType...{virtual ~base2()...{}};
static const bool value = (sizeof(base1) == sizeof(base2));
};

template<typename Type>

struct is_polymorphic : bool_<is_polymorphic_helper<Type, is_class<Type>::value>::value>...{};
4. more type property
has_nothrow_assign / has_nothrow_constructor / has_nothrow_copy / has_trivial_assign / has_trivial_constructor / has_trivial_copy / is_pod / is_stateless的实现,都需要编译器支持
5. relationship between types
template<typename type1, typename type2>

struct is_same : false_...{};
template<typename type>

struct is_same<type,type> : true_...{}
is_convertible
template<typename to>
char convertible_helper(to);
template<typename to>
int convertible_helper(...);
template<typename from, typename to>
struct is_convertible_helper

...{
static from m;
static const bool value = (sizeof(convertible_helper<to>(m)) == sizeof(char));
};

template<typename from, typename to>

struct is_convertible : bool_<is_convertible_helper<from,to>::value>...{};
is_base_and_derived
template<typename base, typename derived>

struct is_base_and_derived : bool_<ice_and<is_class<base>::value, is_class<derived>::value, is_convertible<derived, base>::value>::value>...{};

6. type transformation
template<typename Type>
struct remove_const

...{
typedef Type type;
};
template<typename Type>
struct remove_const<const Type>

...{
typedef Type type;
};
template<typename Type>
struct remove_const<const volatile Type>

...{
typedef Type volatile type;
};


template<typename Type>
struct remove_volatile

...{
typedef Type type;
};
template<typename Type>
struct remove_volatile<volatile Type>

...{
typedef Type type;
};
template<typename Type>
struct remove_volatile<const volatile Type>

...{
typedef Type const type;
};
template<typename Type>
struct remove_cv

...{
typedef typename remove_volatile<typename remove_const<Type>::type>::type type;
};


template<typename Type>
struct remove_reference

...{
typedef Type type;
};

template<typename Type>
struct remove_reference<Type&>

...{
typedef Type type;
};
template<typename Type>
struct remove_pointer

...{
typedef Type type;
};

template<typename Type>
struct remove_pointer<Type*>

...{
typedef Type type;
};
template<typename Type>
struct add_reference

...{
typedef Type& type;
};

template<typename Type>
struct add_reference<Type&>

...{
typedef Type type;
};
template<typename Type>
struct add_pointer

...{
typedef Type* type;
};


template<typename Type>
struct add_const

...{
typedef Type const type;
};

template<typename Type>
struct add_const<const Type>

...{
typedef Type type;
};
以上的type_trait实现只在conceptgcc下面测试通过并且测试是相当简单的,给出测试用例,如果需要使用type_trait,我们仍然需要使用boost中的mpl

struct foo...{};


struct vfoo...{virtual ~vfoo()...{}};


struct base...{};

struct derived : base...{};

void bar(int v,char b)

...{}

int main()

...{
typedef int (*funcptr)(int,char);
typedef void (foo::*memfunptr)(int,char);
printf("funcptr is pointer : %d ", is_pointer<funcptr>::value);
printf("int is pointer : %d ", is_pointer<int>::value);
printf("int* is pointer : %d ", is_pointer<int*>::value);
printf("int is class : %d ", is_class<int>::value);
printf("foo is class : %d ", is_class<foo>::value);
printf("int is array : %d ", is_array<int>::value);
printf("int[] is array : %d ", is_array<int[]>::value);
printf("const int[] is array : %d ", is_array<const int[]>::value);
printf("const int[10] is array : %d ", is_array<const int[10]>::value);
printf("const int*[10] is array : %d ", is_array<const int*[10]>::value);
printf("int is reference : %d ", is_reference<int>::value);
printf("int& is reference : %d ", is_reference<int&>::value);
printf("const int& is reference : %d ", is_reference<const int&>::value);

printf("memfunptr is member function pointer : %d ", is_member_pointer<memfunptr>::value);
printf("int is member function pointer : %d ", is_member_pointer<int>::value);
printf("int is arithmetic : %d ", is_arithmetic<int>::value);
printf("int* is arithmetic : %d ", is_arithmetic<int*>::value);
printf("double is fundamental : %d ", is_fundamental<double>::value);
printf("void is fundamental : %d ", is_fundamental<void>::value);
printf("void* is fundamental : %d ", is_fundamental<void*>::value);
printf("foo is compound : %d ", is_compound<foo>::value);
printf("int is compound : %d ", is_compound<int>::value);
printf("int[] is compound : %d ", is_compound<int[]>::value);
printf("int is object : %d ", is_object<int>::value);
printf("int& is object : %d ", is_object<int&>::value);
printf("foo is object : %d ", is_object<foo>::value);
printf("funcptr is object : %d ", is_object<funcptr>::value);
printf("int is scalar : %d ", is_scalar<int>::value);
printf("int& is scalar : %d ", is_scalar<int&>::value);
printf("foo alignment : %d ", alignment_of<foo>::value);
printf("void alignment : %d ", alignment_of<void>::value);
printf("long double alignment : %d ", alignment_of<long double>::value);
printf("int is empty : %d ", is_empty<int>::value);
printf("foo is empty : %d ", is_empty<foo>::value);
printf("foo is polymorphic : %d ", is_polymorphic<foo>::value);
printf("int is polymorphic : %d ", is_polymorphic<int>::value);
printf("vfoo is polymorphic : %d ", is_polymorphic<vfoo>::value);
printf("int float is convertible : %d ", is_convertible<int,float>::value);
printf("int* float* is convertible : %d ", is_convertible<int*,float*>::value);
printf("double float is convertible : %d ", is_convertible<double,float>::value);
printf("foo vfoo is convertible : %d ", is_convertible<foo, vfoo>::value);
printf("base derived is convertible : %d ", is_convertible<base, derived>::value);
printf("derived base is convertible : %d ", is_convertible<derived, base>::value);
return 0;
}
附带上部分习题解答:
#include <typeinfo>
#include <cstdio>
#include <stdbool.h>
#include <string.h>
#include <iostream>
using namespace std;

template<typename type1, typename type2>
struct is_same

...{
const static bool value = false;
};


template<typename type>
struct is_same<type,type>

...{
const static bool value = true;
};

#if 0
template<typename Type>
struct add_const_ref

...{
typedef const Type& type;
};

template<typename Type>
struct add_const_ref<const Type>

...{
typedef const Type& type;
};

template<typename Type>
struct add_const_ref<volatile Type>

...{
typedef const Type& type;
};

template<typename Type>
struct add_const_ref<const volatile Type>

...{
typedef const Type& type;
};

template<typename Type>
struct add_const_ref<Type&>

...{
typedef Type type;
};


template<typename Type>
struct add_const_ref<const Type&>

...{
typedef Type type;
};


template<typename Type>
struct add_const_ref<volatile Type&>

...{
typedef Type type;
};


template<typename Type>
struct add_const_ref<const volatile Type&>

...{
typedef Type type;
};

template<typename c, typename x, typename y>
struct replace_type

...{
typedef c type;
};

template<typename c, typename x, typename y>
struct replace_type<const c, x, y>

...{
typedef typename replace_type<c,x,y>::type const type;
};

template<typename c, typename x, typename y>
struct replace_type<volatile c, x, y>

...{
typedef typename replace_type<c,x,y>::type volatile type;
};

template<typename c, typename x, typename y>
struct replace_type<const volatile c, x, y>

...{
typedef typename replace_type<c,x,y>::type const volatile type;
};

template<typename x, typename y>
struct replace_type<x,x,y>

...{
typedef y type;
};

template<typename x, typename y>
struct replace_type<const x,x,y>

...{
typedef y const type;
};

template<typename x, typename y>
struct replace_type<volatile x,x,y>

...{
typedef y volatile type;
};

template<typename x, typename y>
struct replace_type<const volatile x,x,y>

...{
typedef y const volatile type;
};

template<typename c, typename x, typename y>
struct replace_type<c&, x, y>

...{
typedef typename replace_type<c,x,y>::type& type;
};

template<typename c, typename x, typename y>
struct replace_type<c*, x, y>

...{
typedef typename replace_type<c,x,y>::type* type;
};

template<typename c, typename x, typename y, int size>
struct replace_type<c[size],x,y>

...{
typedef typename replace_type<c,x,y>::type tempType;
typedef tempType type[size];
};

template<typename c, typename x, typename y>
struct replace_type<c(*)(),x,y>

...{
typedef typename replace_type<c,x,y>::type retType;
typedef retType (*type)();
};

template<typename c, typename arg1, typename x, typename y>
struct replace_type<c(*)(arg1),x,y>

...{
typedef typename replace_type<c,x,y>::type retType;
typedef typename replace_type<arg1,x,y>::type arg1Type;
typedef retType (*type)(arg1Type);
};

template<typename c, typename arg1, typename arg2, typename x, typename y>
struct replace_type<c(*)(arg1,arg2),x,y>

...{
typedef typename replace_type<c,x,y>::type retType;
typedef typename replace_type<arg1,x,y>::type arg1Type;
typedef typename replace_type<arg2,x,y>::type arg2Type;
typedef retType (*type)(arg1Type,arg2Type);
};

// 原来想通过variadic template实现,尝试后未能成功
template<typename c, typename ClassType, typename x, typename y>
struct replace_type<c(ClassType::*)(),x,y>

...{
typedef typename replace_type<c,x,y>::type retType;
typedef typename replace_type<ClassType,x,y>::type classType;
typedef retType (classType::*type)();
};

template<typename c, typename ClassType, typename arg1, typename x, typename y>
struct replace_type<c(ClassType::*)(arg1),x,y>

...{
typedef typename replace_type<c,x,y>::type retType;
typedef typename replace_type<ClassType,x,y>::type classType;
typedef typename replace_type<arg1,x,y>::type arg1Type;
typedef retType (classType::*type)(arg1Type);
};

template<typename c, typename ClassType, typename arg1, typename arg2, typename x, typename y>
struct replace_type<c(ClassType::*)(arg1,arg2),x,y>

...{
typedef typename replace_type<c,x,y>::type retType;
typedef typename replace_type<ClassType,x,y>::type classType;
typedef typename replace_type<arg1,x,y>::type arg1Type;
typedef typename replace_type<arg2,x,y>::type arg2Type;
typedef retType (classType::*type)(arg1Type,arg2Type);
};
#endif

template<typename Type>

struct type_descriptor...{
static const char *name;
operator const char*()

...{
return name;
}
};


template<typename Type> const char* type_descriptor<Type>::name = "Unknow type";
template<> const char* type_descriptor<char>::name = "char";
template<> const char* type_descriptor<const char>::name = "const char";
template<> const char* type_descriptor<volatile char>::name = "volatile char";
template<> const char* type_descriptor<const volatile char>::name = "const volatile char";
template<> const char* type_descriptor<unsigned char>::name = "unsigned char";
template<> const char* type_descriptor<const unsigned char>::name = "const unsigned char";
template<> const char* type_descriptor<volatile unsigned char>::name = "volatile unsigned char";
template<> const char* type_descriptor<const volatile unsigned char>::name = "const volatile unsigned char";
template<> const char* type_descriptor<signed char>::name = "signed char";
template<> const char* type_descriptor<const signed char>::name = "const signed char";
template<> const char* type_descriptor<volatile signed char>::name = "volatile signed char";
template<> const char* type_descriptor<const volatile signed char>::name = "const volatile signed char";
template<> const char* type_descriptor<short>::name = "short";
template<> const char* type_descriptor<const short>::name = "const short";
template<> const char* type_descriptor<volatile short>::name = "volatile short";
template<> const char* type_descriptor<const volatile short>::name = "const volatile short";
template<> const char* type_descriptor<unsigned short>::name = "unsigned short";
template<> const char* type_descriptor<const unsigned short>::name = "const unsigned short";
template<> const char* type_descriptor<volatile unsigned short>::name = "volatile unsigned short";
template<> const char* type_descriptor<const volatile unsigned short>::name = "const volatile unsigned short";
template<> const char* type_descriptor<int>::name = "int";
template<> const char* type_descriptor<const int>::name = "const int";
template<> const char* type_descriptor<volatile int>::name = "volatile int";
template<> const char* type_descriptor<const volatile int>::name = "const volatile int";
template<> const char* type_descriptor<unsigned int>::name = "unsigned int";
template<> const char* type_descriptor<const unsigned int>::name = "const unsigned int";
template<> const char* type_descriptor<volatile unsigned int>::name = "volatile unsigned int";
template<> const char* type_descriptor<const volatile unsigned int>::name = "const volatile unsigned int";
template<> const char* type_descriptor<long>::name = "long";
template<> const char* type_descriptor<const long>::name = "const long";
template<> const char* type_descriptor<volatile long>::name = "volatile long";
template<> const char* type_descriptor<const volatile long>::name = "const volatile long";
template<> const char* type_descriptor<unsigned long>::name = "unsigned long";
template<> const char* type_descriptor<const unsigned long>::name = "const unsigned long";
template<> const char* type_descriptor<volatile unsigned long>::name = "volatile unsigned long";
template<> const char* type_descriptor<const volatile unsigned long>::name = "const volatile unsigned long";
template<> const char* type_descriptor<long long>::name = "long long";
template<> const char* type_descriptor<const long long>::name = "const long long";
template<> const char* type_descriptor<volatile long long>::name = "volatile long long";
template<> const char* type_descriptor<const volatile long long>::name = "const volatile long long";
template<> const char* type_descriptor<unsigned long long>::name = "unsigned long long";
template<> const char* type_descriptor<const unsigned long long>::name = "const unsigned long long";
template<> const char* type_descriptor<volatile unsigned long long>::name = "volatile unsigned long long";
template<> const char* type_descriptor<const volatile unsigned long long>::name = "const volatile unsigned long long";
template<> const char* type_descriptor<float>::name = "float";
template<> const char* type_descriptor<const float>::name = "const float";
template<> const char* type_descriptor<volatile float>::name = "volatile float";
template<> const char* type_descriptor<const volatile float>::name = "const volatile float";
template<> const char* type_descriptor<double>::name = "double";
template<> const char* type_descriptor<const double>::name = "const double";
template<> const char* type_descriptor<volatile double>::name = "volatile double";
template<> const char* type_descriptor<const volatile double>::name = "const volatile double";
template<> const char* type_descriptor<long double>::name = "long double";
template<> const char* type_descriptor<const long double>::name = "const long double";
template<> const char* type_descriptor<volatile long double>::name = "volatile long double";
template<> const char* type_descriptor<const volatile long double>::name = "const volatile long double";

template<typename Type>

struct type_descriptor<Type*>...{
operator const char*()

...{
static char name[1024];
strcpy(name, "pointer to ");
strcat(name, type_descriptor<Type>());
return name;
}
};

template<typename Type>

struct type_descriptor<Type&>...{
operator const char*()

...{
static char name[1024];
strcpy(name, "reference to ");
strcat(name, type_descriptor<Type>());
return name;
}
};

template<typename Type, int size>

struct type_descriptor<Type[size]>...{
operator const char*()

...{
static char name[1024];
strcpy(name, "array of ");
strcat(name, type_descriptor<Type>());

char temp[256] = ...{0};
sprintf(temp, " which size = %d", size);
strcat(name, temp);
return name;
}
};

template<typename retType>
struct type_descriptor<retType(*)()>

...{
operator const char*()

...{
static char name[1024];
strcpy(name, "function return ");
strcat(name, type_descriptor<retType>());
strcat(name, " and has no argument");
return name;
}
};

template<typename retType, typename argType>
struct type_descriptor<retType(*)(argType)>

...{
operator const char*()

...{
static char name[1024];
strcpy(name, "function return ");
strcat(name, type_descriptor<retType>());
strcat(name, " and with ");
strcat(name, type_descriptor<argType>());
strcat(name, " as first argument");
return name;
}
};

template<typename retType, typename arg1Type, typename arg2Type>
struct type_descriptor<retType(*)(arg1Type, arg2Type)>

...{
operator const char*()

...{
static char name[1024];
strcpy(name, "function return ");
strcat(name, type_descriptor<retType>());
strcat(name, " and with ");
strcat(name, type_descriptor<arg1Type>());
strcat(name, " as first argument, ");
strcat(name, type_descriptor<arg2Type>());
strcat(name, " as second argument");
return name;
}
};

int main()

...{
cout<<"type_descriptor<const int* (*)(char& (*)(short), double*)>" << type_descriptor<const int* (*)(char& (*)(short), double*)>();
printf("add_const_ref<int>::type = %s ", typeid(add_const_ref<int>::type).name());
printf("add_const_ref<int>::type == const int& : %d ", is_same<add_const_ref<int>::type, const int&>::value);
printf("add_const_ref<volatile int>::type == const int& : %d ", is_same<add_const_ref<volatile int>::type, const int&>::value);
printf("add_const_ref<volatile int&>::type == int : %d ", is_same<add_const_ref<volatile int&>::type, int>::value);

printf("replace_type<int,int,char>::type == char : %d ", is_same<replace_type<int,int,char>::type, char>::value);
printf("replace_type<const int,int,char>::type == char : %d ", is_same<replace_type<const int,int,char>::type, const char>::value);
printf("replace_type<int(*)(int,char),int,short>::type == short(*)(short,char) : %d ", is_same<replace_type<int(*)(int,char),int,short>::type, short(*)(short,char)>::value);
printf("replace_type<int(*)(const int,int (*)()),int,short>::type == short(*)(const short, short(*)()) : %d ", is_same<replace_type<int(*)(const int, int(*)()),int,short>::type, short(*)(const short,short(*)())>::value);
printf("replace_type<int[10],int,char>::type == char[10] : %d ", is_same<replace_type<int[10],int,char>::type, char[10]>::value);
printf("replace_type<int[10],int,char>::type = %s ", typeid(replace_type<int[10],int,char>::type).name());
printf("replace_type<int[10],char,char>::type == int[10] : %d ", is_same<replace_type<int[10],char,char>::type, int[10]>::value);
printf("replace_type<int[10],char,char>::type = %s ", typeid(replace_type<int[10],char,char>::type).name());
return 0;
}