2010-02-21 2 views
5

Этот вопрос относится к моим последним one. Я пытаюсь решить проблему, используя traits<T> и traits<T*>. Пожалуйста, рассмотрите следующий код.Использование черт в C++

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 
    return 0; 
} 

Так это выглядит как компилятор не рассматривает черты специализации для указателей и принимая тип возвращаемого из value() в const foo, а не const foo*. Что я здесь делаю неправильно?

Любая помощь будет замечательной!

ответ

2

Специализация используется. traits<foo*>::const_referenceявляетсяconst foo. Если вы хотите, чтобы быть указателем, используйте:

template<typename T> 
struct traits<T*> 
{ 
    typedef const T* const_reference; 
}; 

С этим traits<foo*>::const_reference будет const foo*.

Обратите внимание, что использование T в специализации traits<T*> полностью отделено от T в шаблоне traits. Вы можете переименовать его:

template<typename U> 
struct traits<U*> 
{ 
    typedef const U* const_reference; 
}; 

и у вас будет такая же специализация. Это имеет смысл, если у вас есть опыт в функциональном программировании.

Чтобы начать, подумайте о template <typename ...> как введение абстракции, а как функцию абстрагирует значение. Это как превращение

sum = 0 
for item in [1,2,3]: 
    sum += item 

в:

function sum(l): 
    sum = 0 
    for item in l: 
     sum += item 
    return sum 

где l занимает место [1,2,3]. Мы можем назвать sums из другой функции, которая сама по себе имеет формальный параметр с именем l:

function sumsq(l): 
    return sum(map(lambda x: x*x, l)) 

sumsq «s„л“не имеет ничего общего с sum» „л“ s.

С шаблонами мы выделяем имена типов, а не значения. То есть, мы переходим:

struct traits { 
    typedef const double& const_reference; 
}; 

в:

template <typename T> 
struct traits { 
    typedef const T& const_reference; 
}; 

Теперь рассмотрим без специализации шаблона:

template <> 
struct traits<double*> { 
    typedef const double* const_reference; 
}; 

Здесь нет никаких параметров шаблона для специализации, но вы можете подумайте о traits<double*> как применяете шаблон traits к double*. Аннотация вне double и у вас есть:

template <typename T> 
struct traits<T*> { 
    typedef const T* const_reference; 
}; 

Здесь T является параметром для специализации, а не базовый шаблон.

+0

Я чувствую дамп :(Но сам T является указателем ('foo *'). Таким образом, указание 'T *' приведет к 'T **'? –

+0

№. В 'traits ' специализация 'T 'не является указателем,' T * 'является указателем. То, что вы используете один и тот же параметр, является несущественным. – outis

+0

ОК. Спасибо. Теперь это имеет смысл. –

Смежные вопросы