Определить норму как функцию-член векторного класса в C

#c #vector #c -standard-library

#c #вектор #c -standard-library

Вопрос:

Я пытаюсь написать свой собственный векторный класс на C .В частности, я хочу реализовать норму как функцию-член. Следующий классический фрагмент кода — это то, что я сделал:

 #include <iostream>
#include <cmath>

template <typename T>
class vector{
private:
    T* elem;
    std::size_t _size;
public:
    vector(const std::size_t size) : elem{new T[size]}, _size{size} {}
    ~vector(){ delete[] elem;}
    std::size_t size() const { return _size;}
    Tamp; operator[](std::size_t i){ return elem[i];}
    const Tamp; operator[](std::size_t i) const{ return elem[i];}
    friend T norm();
};

template <typename T>
T vector::norm(){
    T sum{0};
    for (auto i=0u;i<_size;  i){
        sum =elem[i];
    }
    return std::sqrt(sum);
}

int main(){
    vector<double> v{10};
    for (auto i=0u;i<v.size();  i){
        v[i] = i;
    }

    std::cout << v.norm() <<std::endl;
    
    return 0;
}
  

Очевидно, что я мог бы определить функцию norm внутри класса, но я хотел определить ее снаружи, потому что в принципе тело одной из функций-членов может быть длиной в несколько строк.

Как только я пытаюсь скомпилировать, компилятор сообщает, что:

  • ‘template<class T> class vector’ используется без аргументов шаблона
  • _size , elem не объявленный в области видимости
  • ‘class vector<double>’ не имеет члена с именем ‘norm’

но я не могу понять, что не так, и как это исправить! В частности, я не понимаю последнего пункта: я явно объявлен norm() как функция-член! Как я должен изменить свой код?

Ответ №1:

Вы объявляете norm() как friend функцию, поэтому на самом деле она не является членом самого vector класса. Вы сообщаете компилятору, что некоторая внешняя функция, не являющаяся членом T norm() , является другом vector , чтобы она могла получить доступ vector к закрытым членам. Но тогда вы на самом деле не определяете такую T norm() функцию!

Правильный способ реализации norm() в качестве члена с определением вне объявления класса будет выглядеть следующим образом:

 template <typename T>
class vector{
    ...
public:
    ...
    T norm(); // <-- remove 'friend'!
};

template <typename T>
T vector<T>::norm(){ // <-- note the extra <T>!
    T sum{0};
    for (auto i = 0u; i < _size;   i){
        sum  = elem[i];
    }
    return std::sqrt(sum);
}
  

На заметку:

Вы могли бы рассмотреть возможность использования SFINAE, чтобы опустить объявление определение типов norm() for T , которые std::sqrt() не поддерживаются (нецелые числа / типы с плавающей запятой, такие как строки и т. Д.).

Кроме того, ваш vector класс не реализует правило 3/5/0 для правильного управления своим внутренним массивом. Вам нужно добавить к нему соответствующие конструкторы копирования / перемещения и операторы присваивания копирования / перемещения.

Комментарии:

1. Понятно, спасибо! Таким образом, я все еще могу получить доступ к данным-членам, т. Е. elem И _size , Когда я нахожусь вне класса, верно?

2. Я только начал введение в классы, и это первая часть. Я пытался добавить норму самостоятельно, но я застрял, как вы видели 🙂

3. @Vefhug » Я все еще могу получить доступ к данным-членам… когда я нахожусь вне класса, верно? » — если вы правильно объявите norm() как член и закодируете его определение с правильным синтаксисом, чтобы компилятор знал, на какой экземпляр vector смотреть, тогда да, ваше внешнее определение norm() может получить доступ к данным члена vector . » Я только начал введение в классы » — какое введение вы используете, которое сразу переходит к использованию шаблонов и разделению объявлений из определений элементов шаблона? Это довольно сложные темы для ознакомления с классами.