Используя черты в C++

Этот вопрос связан с моим последним. Я пытаюсь решить использование задач 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*. Что я делаю неправильно здесь?

Любая справка была бы большой!

6
задан Community 23 May 2017 в 10:24
поделиться

1 ответ

Используется специализация. traits::const_reference is const foo. Если вы хотите, чтобы это был указатель, используйте:

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

С помощью этого, traits::const_reference будет 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 является параметром специализации, а не базового шаблона.

2
ответ дан 17 December 2019 в 20:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: