Этот вопрос связан с моим последним. Я пытаюсь решить использование задач traits
и traits
. Рассмотрите следующий код.
template
struct traits
{
typedef const T& const_reference;
};
template
struct traits
{
typedef const T const_reference;
};
template
class test
{
public:
typedef typename traits::const_reference const_reference;
test() {}
const_reference value() const {
return f;
}
private:
T f;
};
int main()
{
const test t;
const foo* f = t.value(); // error here. cannot convert ‘const foo’ to ‘const foo*’ in initialization
return 0;
}
Таким образом, похоже, что компилятор не рассматривает специализации черт для указателей и берет тип возврата value()
как const foo
вместо const foo*
. Что я делаю неправильно здесь?
Любая справка была бы большой!
Используется специализация. traits
is const foo
. Если вы хотите, чтобы это был указатель, используйте:
template<typename T>
struct traits<T*>
{
typedef const T* const_reference;
};
С помощью этого, traits
будет const foo*
.
Обратите внимание, что использование T
в специализации traits
полностью отделено от T в шаблоне traits
. Вы можете переименовать его:
template<typename U>
struct traits<U*>
{
typedef const U* const_reference;
};
и у вас будет та же специализация. Это имеет больше смысла, если у вас есть опыт функционального программирования.
Для начала подумайте о шаблоне
как о введении абстракции, подобно тому, как функция абстрагирует значение. Это все равно что превратить
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))
"l" sumsq
не имеет ничего общего с "l" sum
.
С помощью шаблонов мы абстрагируем имена типов, а не значения. То есть, мы превращаем:
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
как о применении шаблона traits
к double*
. Абстрагируйте double
и получите:
template <typename T>
struct traits<T*> {
typedef const T* const_reference;
};
Здесь T
является параметром специализации, а не базового шаблона.