1

Тема: шаблоний класс з дружньою функцією перезавантаженного оператора

Всім привіт, вивчаю С++, для вправи вирішив написати клас який реалізує роботу "стеку". Зіткнувся з такою проблемою. Якщо я залишаю все як є, але прибираю шаблоний тип uniVar(замість нього вказую char) все працює. Якщо я прибираю дружні функції і залишаю шаблоний тип uniVar також все працює. Але якщо я використовую і те і інше в мене виникає помилка яку усунути я не знаю як. Допоможіть студенту у вивчені C++ :)

#include <iostream>
#define STEK_SIZE 512
using namespace std;




template <typename uniVar>
class stek{
private:
    uniVar st[STEK_SIZE];
    int pos;
public:
    bool operator << (uniVar &val){
        if(pos+1 < STEK_SIZE){
            st[++pos] = val;
            return true;
        }else{
            return false;
        }
    }

    bool operator >> (uniVar &val){
        if(pos > -1){
            val = st[pos--];
            return true;
        }else{
            return false;
        }
    }
    
    friend bool operator << (uniVar &val, stek &ob);
    friend bool operator >> (uniVar &val, stek &ob);
    stek(){
        pos = -1;    
    }
};


bool operator >> (uniVar &val, stek &ob){
        if(ob.pos+1 < STEK_SIZE){
            ob.st[++ob.pos] = val;
            return true;
        }else{
            return false;
        }
}


bool operator << (uniVar &val, stek &ob){
        if(ob.pos > -1){
            val = ob.st[ob.pos--];
            return true;
        }else{
            return false;
        }
}


int main(){
char sym;    
char buffer[] = "hello world";
    stek<char> Stek;

    Stek << buffer[10];
    Stek << buffer[9];
    Stek << buffer[8];
    Stek << buffer[7];
    Stek << buffer[6];
    Stek << buffer[5];
    Stek << buffer[4];
    Stek << buffer[3];
    Stek << buffer[2];
    buffer[1] >> Stek;
    buffer[0] >> Stek;
    while(Stek >> sym){
        cout << sym;
    }
    cout << endl;
    cout << "C++ work" << endl;
    return 0;
}

2

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

Якщо є повідомлення про помилку, наводьте його в питанні. З телепатією тут у людей не дуже, а розбирати чужий код не завжди і не всім цікаво (особливо якщо він невирівняний, як у вас).

Як я бачу, проблема через шаблонність і область видимості:

template <typename uniVar>                 //область видимості uniVar почалася
class stek{...};                           //область видимості uniVar скінчилася
bool operator >> (uniVar &val, stek &ob){  //що таке uniVar? і чому нешаблонний operator>> буде працювати із шаблонним стеком?

Щоб вирішити її, треба проголосити ваших друзів теж шаблонними функціями:

template <typename uniVar>          
bool operator >> (uniVar &val, stek<uniVar> &ob){ 
Подякували: Arete, 2andnot2

3 Востаннє редагувалося 2andnot (02.06.2017 11:55:45)

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

Невирівняний тому що писав в "блокноті".
Зробив, як Ви писали, все одно не хоче.

#include <iostream>
#define STEK_SIZE 512
using namespace std;




template <typename uniVar>
class stek{
private:
    uniVar st[STEK_SIZE];
    int pos;
public:
    bool operator << (uniVar &val){
        if(pos+1 < STEK_SIZE){
            st[++pos] = val;
            return true;
        }else{
            return false;
        }
    }

    bool operator >> (uniVar &val){
        if(pos > -1){
            val = st[pos--];
            return true;
        }else{
            return false;
        }
    }
    
    friend bool operator << (uniVar &val, stek &ob);
    friend bool operator >> (uniVar &val, stek &ob);
    stek(){
        pos = -1;    
    }
};

template <typename uniVar>          
bool operator >> (uniVar &val, stek<uniVar> &ob){
        if(ob.pos+1 < STEK_SIZE){
            ob.st[++ob.pos] = val;
            return true;
        }else{
            return false;
        }
}

template <typename uniVar>          
bool operator >> (uniVar &val, stek<uniVar> &ob){
        if(ob.pos > -1){
            val = ob.st[ob.pos--];
            return true;
        }else{
            return false;
        }
}


int main(){
char sym;    
char buffer[] = "hello world";
    stek<char> Stek;

    Stek << buffer[10];
    Stek << buffer[9];
    Stek << buffer[8];
    Stek << buffer[7];
    Stek << buffer[6];
    Stek << buffer[5];
    Stek << buffer[4];
    Stek << buffer[3];
    Stek << buffer[2];
    buffer[1] >> Stek;
    buffer[0] >> Stek;
    while(Stek >> sym){
        cout << sym;
    }
    cout << endl;
    cout << "C++ work" << endl;
    return 0;
}

Ось що пише компілятор

boris@eldorado:~/Desktop$ g++ main.cpp -o main.com
main.cpp:32:48: warning: friend declaration ‘bool operator<<(uniVar&, stek<uniVar>&)’ declares a non-template function [-Wnon-template-friend]
main.cpp:32:48: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
main.cpp:33:48: warning: friend declaration ‘bool operator>>(uniVar&, stek<uniVar>&)’ declares a non-template function [-Wnon-template-friend]
main.cpp:50:6: error: redefinition of ‘template<class uniVar> bool operator>>(uniVar&, stek<uniVar>&)’
main.cpp:40:6: error: ‘template<class uniVar> bool operator>>(uniVar&, stek<uniVar>&)’ previously declared here
boris@eldorado:~/Desktop$

4

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

Проголошення френдів всередині класу теж поміняйте, вони мають бути шаблонними.

І новий код теж викладайте, я вже писав - з телепатією тут проблеми.

5

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

#include <iostream>
#define STEK_SIZE 512
using namespace std;




template <typename uniVar>
class stek{
private:
    uniVar st[STEK_SIZE];
    int pos;
public:
    bool operator << (uniVar &val){
        if(pos+1 < STEK_SIZE){
            st[++pos] = val;
            return true;
        }else{
            return false;
        }
    }

    bool operator >> (uniVar &val){
        if(pos > -1){
            val = st[pos--];
            return true;
        }else{
            return false;
        }
    }
    template <typename uniVar>  
    friend bool operator << (uniVar &val, stek<uniVar> &ob);
    template <typename uniVar>      
    friend bool operator >> (uniVar &val, stek<uniVar> &ob);
    stek(){
        pos = -1;    
    }
};

template <typename uniVar>          
bool operator >> (uniVar &val, stek<uniVar> &ob){
        if(ob.pos+1 < STEK_SIZE){
            ob.st[++ob.pos] = val;
            return true;
        }else{
            return false;
        }
}

template <typename uniVar>          
bool operator << (uniVar &val, stek<uniVar> &ob){
        if(ob.pos > -1){
            val = ob.st[ob.pos--];
            return true;
        }else{
            return false;
        }
}


int main(){
char sym;    
char buffer[] = "hello world";
    stek<char> Stek;

    Stek << buffer[10];
    Stek << buffer[9];
    Stek << buffer[8];
    Stek << buffer[7];
    Stek << buffer[6];
    Stek << buffer[5];
    Stek << buffer[4];
    Stek << buffer[3];
    Stek << buffer[2];
    buffer[1] >> Stek;
    buffer[0] >> Stek;
    while(Stek >> sym){
        cout << sym;
    }
    cout << endl;
    cout << "C++ work" << endl;
    return 0;
}

Компілятор пише:

boris@eldorado:~/Desktop$ g++ main.cpp -o main.com
main.cpp:31:12: error: declaration of ‘class uniVar’
main.cpp:8:11: error:  shadows template parm ‘class uniVar’
main.cpp:33:12: error: declaration of ‘class uniVar’
main.cpp:8:11: error:  shadows template parm ‘class uniVar’
boris@eldorado:~/Desktop$

6

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

Помилка вирішилась завдяки додаванню

<uniVar>

в дружню функцію при об’явленні її в тілі классу, тобто так:

friend bool operator << <uniVar>(uniVar &val, stek &ob);     
    friend bool operator >> <uniVar>(uniVar &val, stek &ob);

тепер код має такий вигляд

#include <iostream>
#define STEK_SIZE 512
using namespace std;




template <typename uniVar>
class stek{
private:
    uniVar st[STEK_SIZE];
    int pos;
public:
    bool operator << (uniVar &val){
        if(pos+1 < STEK_SIZE){
            st[++pos] = val;
            return true;
        }else{
            return false;
        }
    }

    bool operator >> (uniVar &val){
        if(pos > -1){
            val = st[pos--];
            return true;
        }else{
            return false;
        }
    } 
    friend bool operator << <uniVar>(uniVar &val, stek &ob);     
    friend bool operator >> <uniVar>(uniVar &val, stek &ob);
    stek(){
        pos = -1;    
    }
};

template <typename uniVar>          
bool operator >> (uniVar &val, stek &ob){
        if(ob.pos+1 < STEK_SIZE){
            ob.st[++ob.pos] = val;
            return true;
        }else{
            return false;
        }
}

template <typename uniVar>          
bool operator << (uniVar &val, stek &ob){
        if(ob.pos > -1){
            val = ob.st[ob.pos--];
            return true;
        }else{
            return false;
        }
}


int main(){
char sym;    
char buffer[] = "hello world";
    stek<char> Stek;

    Stek << buffer[10];
    Stek << buffer[9];
    Stek << buffer[8];
    Stek << buffer[7];
    Stek << buffer[6];
    Stek << buffer[5];
    Stek << buffer[4];
    Stek << buffer[3];
    Stek << buffer[2];
    buffer[1] >> Stek;
    buffer[0] >> Stek;
    while(Stek >> sym){
        cout << sym;
    }
    cout << endl;
    cout << "C++ work" << endl;
    return 0;
}

дякую всім хто допомагав :)

Подякували: koala, Arete2

7

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

В класі stek ви використовуєте шаблонний параметр uniVar, в френдових функціях ви також використовуєте шаблонний параметр який називається точно так же - uniVar. Компілятор схоже не розуміє який з двох uniVar викорстовувати в сигнатурі операторів (uniVar &val, stek<uniVar> &ob), бо для нього це два різні параметри які називаються однаково.

З.І. Можна й так як ви зробили, то повна спеціалізація шаблонної функції. Доречі компілятору в VS2015 такий варіант не подобається.

8

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

Можу порадити ще:
- повертати з функції не bool, а stek<uniVar>& і return *this, тоді можна буде робити

'a'>>Stek<<'b'<<'c';

- взагалі не використовувати френдів, а в шаблонних операторах поза класом викликати оператори класу:

template <typename uniVar>          
bool operator >> (uniVar &val, stek<uniVar> &ob){
       return ob<<val;
}

І так, мені не вдалося його розкочегарити: http://ideone.com/7qMyqj. Буду радий, якщо хтось пояснить, що відбувається.

9

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

Прошу вибачити за дурне питання, бо я тільки вчусь. я правильно зрозумів що для того щоб перевантажити оператор, не обов’язково щоб він був функцією-членом классу або дружньою функцією классу?

Поясніть будь-ласка, що відбуваеться тут?

bool operator >> (uniVar &val, stek<uniVar> &ob)

stek<uniVar>

навіщо біля классу stek йде запис <uniVar>, якщо перед описом классу була інструкція

template <typename uniVar>

10

Re: шаблоний класс з дружньою функцією перезавантаженного оператора

Перевантажений оператор в C++ - просто особливий спосіб запису запису функції. Записи
f(a,b)
a.f(b)
a+b
по суті зводяться до одного й того самого: a, b та адреса повернення (тобто наступної операції) заносяться до стеку викликів і управління передається на адресу першої команди функції f (яка в останньому випадку зветься "operator+"). Ну, ще в другій формі може відбуватися вибір з таблиці віртуальних функцій, але це окреме питання.
Все, що робить проголошення функції дружньою до класу - відкриває їй доступ до private та protected членів. Якщо вона викликає тільки public, то можна її і не робити дружньою.

По другому - а хто нам заборонить робити

template <typename uniVar>
bool operator >> (uniVar &val, stek<string> &ob)

?
uviVar - параметр шаблону; а які параматри у самої функції - це питання програміста. Головне - щоб воно працювало і мало сенс.