先谈谈什么是Traits,BS的解释如下:
Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details". - Bjarne Stroustrup
可以参考这里。所谓Call Traits就是调用时需要的Traits。 Call Traits中文文档看下基本就明白啥意思了。我感觉最大的作用是在写模版类/模版函数传递参数时,保证没有“引用的引用”的情况发生,并且总以最高效的形式传递参数。所谓的最高效形式的规则类似JAVA,(仅仅是类似)即原生的类型就使用传值方式,对象就采用传引用方式。这里有个中文的例子。
正常情况下,一个函数在C++中要么以传值方式传递参数,要么以传引用的方式传递,没法两者兼得:
template <class T>
class TestClass {
public:
TestClass(T value) {
}
TestClass(const T& value) {
}
T value_;
};
在使用时会报错:
error C2668: 'TestClass<T>::TestClass' : ambiguous call to overloaded function
因为C++的函数重载规则并没有规定在这种情况下会调用哪一个函数,导致二义性。
使用Call_Traits的param_type作为参数类型时,以下例子:
int g_i = 0;
class PrintClass {
public:
PrintClass() {
printf("PrintClass created");
++g_i;
}
};
template <class T>
class TestClass {
public:
TestClass(typename boost::call_traits<T>::param_type value) : value_(value){
}
T value_;
};
TestClass<int> test(10);
PrintClass printClass;
TestClass<PrintClass> testPrintClass(printClass);
g_i会等于1,实际因为传递的typename boost::call_traits<T>::param_type value在参数类型是PrintClass(一个对象)时,传递的是引用。同时,我没有想到更好的办法去验证在传递的参数是int类型时,的确是通过时传值。这样说来就很有意思了,因为即使我们在使用模版时函数全部通过传值方式来设计,会在T是对象时导致很大的额外开销,我们全部通过const T&的方式来传递参数就好了,就算是原生类型,这种额外开销还是小到足够忽略不计的,只是,boost库的制作者觉得这样还是不够完美?
同时,Call Traits还解决一个问题,那就是"引用的引用",比如上例中T为T&时的情况..........函数参数假如是通过传递引用的方式的话,const T&的参数,T又等于T&,那么就是const T&&了,C++中没有引用的引用这种东西的存在(只有指针的指针),事实上,Call Traits给函数的调用和参数的类型有完整的一套解决方案,如boost文档中的example 1:
template <class T>
struct contained
{
// define our typedefs first, arrays are stored by value
// so value_type is not the same as result_type:
typedef typename boost::call_traits<T>::param_type param_type;
typedef typename boost::call_traits<T>::reference reference;
typedef typename boost::call_traits<T>::const_reference const_reference;
typedef T value_type;
typedef typename boost::call_traits<T>::value_type result_type;
// stored value:
value_type v_;
// constructors:
contained() {}
contained(param_type p) : v_(p){}
// return byval:
result_type value() { return v_; }
// return by_ref:
reference get() { return v_; }
const_reference const_get()const { return v_; }
// pass value:
void call(param_type p){}
};