Using traits in C++
This question is related to my last one. I am trying to solve the problem using traits<T>
and traits<T*>
. Please consider the following code.
template<typename T>
struct traits
{
typedef const T& const_reference;
};
template<typename T>
struct traits<T*>
{
typedef const T const_reference;
};
template<typename T>
class test
{
public:
typedef typename traits<T>::const_reference const_reference;
test() {}
const_reference value() const {
return f;
}
private:
T f;
};
int main()
{
const test<foo*> t;
const foo* f = t.value(); // error here. cannot convert ‘const foo’ to ‘const foo*’ in initialization
开发者_如何学JAVA return 0;
}
So it looks like compiler is not considering the traits specialization for pointers and taking return type of value()
as const foo
rather than const foo*
. What am I doing wrong here?
Any help would be great!
The specialization is being used. traits<foo*>::const_reference
is const foo
. If you want it to be a pointer, use:
template<typename T>
struct traits<T*>
{
typedef const T* const_reference;
};
With this, traits<foo*>::const_reference
will be const foo*
.
Note that the use of T
in the traits<T*>
specialization is completely separate from the T in the traits
template. You could rename it:
template<typename U>
struct traits<U*>
{
typedef const U* const_reference;
};
and you'll have the same specialization. It makes more sense if you've experience in functional programming.
To start, think of the template <typename ...>
as introducing an abstraction, rather like a function abstracts out a value. It's like turning
sum = 0
for item in [1,2,3]:
sum += item
into:
function sum(l):
sum = 0
for item in l:
sum += item
return sum
where l
takes the place of [1,2,3]
. We can call sums
from another function that itself has a formal parameter named l
:
function sumsq(l):
return sum(map(lambda x: x*x, l))
sumsq
's "l" has nothing to do with sum
's "l".
With templates, we abstract type names rather than values. That is, we turn:
struct traits {
typedef const double& const_reference;
};
into:
template <typename T>
struct traits {
typedef const T& const_reference;
};
Now consider a non-template specialization:
template <>
struct traits<double*> {
typedef const double* const_reference;
};
Here there are no template parameters for the specialization, but you can think of traits<double*>
as applying a traits
template to a double*
. Abstract out the double
and you have:
template <typename T>
struct traits<T*> {
typedef const T* const_reference;
};
Here the T
is a parameter for the specialization, not the base template.
精彩评论