"Klasa" does not name a type

0

Z góry muszę napomnieć, iż jestem bardzo początkującym programistą. Mam za zadanie napisać szablon drzewa binarnego i chciałem dodać do niego funkcję przeszukującą to drzewo ale podczas kompilacji wyskakuje mi taki oto błąd 'error: TreeNote does not name a type' i mam pytanie jaki jest tutaj błąd? Czy muszę użyć jakiegoś operatora zakresu w kontekście tej klasy wbudowanej i jakiego ? Przepraszam jeśli jest to jakieś banalne pytanie ale przeszukałem już trochę forów i nie mogłem znaleźć rozwiązania mojego problemu.

plik tmptree.h

#ifndef TMPTREE_H
#define TMPTREE_H

template <class T> class TmpTree
{
    public:
        class TreeNode
        {
            public:
            T Data;
            TreeNode* Parent;
            TreeNode* RightSon;
            TreeNode* LeftSon;
            TreeNode(T& data);


        };
        TreeNode* Root = NULL;
        void Insert (T& newData);
        TreeNode* Search();

    protected:

    private:

};

#endif // TMPTREE_H

plik tmptree.cpp

#include "tmptree.h"



template <class T>  TreeNode* Search(TreeNode* start, T sData)
{
    if(start->Data = sData)
    {
        return start;
    }
    else if(sData < start->Data && start->LeftSon != NULL)
    {
        return Search(start->LeftSon , sData);
    }
    else if(start->RightSon != NULL)
    {
        return Search(start->RightSon , sData);
    }
    return NULL;
}
 
4

Jeśli początkujący to zapraszam tutaj: Newbie

Problemy:

  1. Szablony muszą być widoczne w pełni w miejscu użycia (z wyjątkami na razie dla ciebie nieistotnymi), więc implementacja metody nie może być w .cpp
  2. w pliku tmptree.cpp definiujesz szablon wolnej funkcji Search, a nie metody klasy (zapomniałeś o operatorze zakresu)
  3. nawet gdybyś nie zapomniał, musiałbyś w pełni zdefinioawać zwracany typ przez funkcję (TmpTree<T>::TreeNode*)
0

Z tą wolną funkcją to ta próbowałem jakoś to zmienić żeby zadziałało, a jak wrzucałem kod to nie poprawiłem. Dzięki za pomoc. Jeśli można to chcę zadać jeszcze jedno pytanie.
Otóż chcę zadeklarować specjalizację metody w szablonie klasy no i robię to w taki sposób

template <typename T> class TmpTree
{
    public:
        class TreeNode
        {
            public:
            T Data;
            TreeNode* Parent;
            TreeNode* RightSon;
            TreeNode* LeftSon;
            TreeNode(T& data);


        };
        TreeNode* Root = NULL;
        
        
        void PrintData(T& data)
        {

            std::cout << T << std::endl;
        }

    protected:

    private:
        
};
        template<> void TmpTree<Album>::PrintData(Album& data);

        template<> void TmpTree<Album>::PrintData(Album& data)
        {
            std::cout << "Autor albumu: "<<data.Author <<std::endl;
            std::cout << "Tytul albumu: " << data.Title << std::endl;
            std::cout << "Rok wydania albumu: " << data.PubliDate << std::endl;
        } 

Błąd to multiple definition of `TmpTree<Album>::PrintData(Album&)

Znalazłem gdzieś że kod w tej postaci jest poprawny. Ogólny przykład:

template <typename T>
struct Test {
    void print_type() {
        cout << "Type is: " << typeid(T).name() << "\n";
    }
};
 
 
template<>
void Test<int>::print_type();
 
 
template<>
void Test<int>::print_type() {
    cout << "It's int\n";
} 

Jaka jest różnica w moim kodzie, a tym powyżej że kompilator tego nie przepuszcza, lub jak inaczej można taką metodę zadeklarować?

1

Możesz wyspecjalizować całą klasę, albo samą funkcję (tylko dla w pełni skonkretyzowanych klas). Ciekawe.

0

A czy muszę wtedy definiować wszystkie metody od początku dla klasy wyspecjalizowanej, czy jeśli ich nie zdefiniuje to zostaną użyte te z szablony klasy ogólnej ? Taka specjalizacja częściowa o ile istnieje coś takiego.

1
template<> void TmpTree<Album>::PrintData(Album& data);
 
        template<> void TmpTree<Album>::PrintData(Album& data)
        {}

..multiple definition of 'TmpTree<album>::PrintData(Album&)'

template <typename T> class TmpTree
{
    public:
        class TreeNode
        {
            public:
            T Data;
            TreeNode* Parent;
            TreeNode* RightSon;
            TreeNode* LeftSon;
            TreeNode(T& data);
 
 
        };
        TreeNode* Root = NULL;
 
 
        void PrintData(T& data)
        {
 
            std::cout << T << std::endl;
        }
 //+
    template<> void PrintData(Album& data);
    protected:
 
    private:
 
};
//-    template<> void TmpTree<Album>::PrintData(Album& data);

        template<> void TmpTree<Album>::PrintData(Album& data)
        {
            std::cout << "Autor albumu: "<<data.Author <<std::endl;
            std::cout << "Tytul albumu: " << data.Title << std::endl;
            std::cout << "Rok wydania albumu: " << data.PubliDate << std::endl;
        } 

Definiujesz metody wyspecjalizowane analogicznie jakbyś definiował funkcje do zwyczajnej klasy dla kilku rodzajów zmiennej użytej jako parametr np. class TmpTree { func(T&); func(int&); func(char&); albo func(int&) const; } po czym tworzysz ciała TmpTree::func(int&) { } itd.
W definicji klasy wpisujesz nazwe funkcji jaką chcesz wyspecjalizować z podaniem rodzaju zmiennej dla jakiej chcesz to zrobić. Z tą różnicą że przed definicją i deklaracją ciała musisz użyć słówka: template
Przy tworzeniu ciała zamiast TmpTree<T>::PrintData(T& data) { ciało.. } używasz wyspecjalizowanego typu TmpTree<Album>::PrintData(&Album data) { ciało } ale również rozpoczynasz słówkiem template mówiącym że to funkcja wyspecjalizowana więc:

template<> void TmpTree<Album>::PrintData(Album &data) { ciało.. }

EDIT: dziwne bo porada działała w BCB (na mojej klasie) sprawdziłem też stacoverflow podobne wzory, a w MinGW dla analogicznie wyspecjalizowanej klasy:
"explicit specialization in non namspace scope" Wygląda na to że powyższą porade można sobie wsadzić.
http://en.cppreference.com/w/cpp/language/template_specialization
http://wazniak.mimuw.edu.pl/index.php?title=Zaawansowane_CPP/Wyk%C5%82ad_3:_Szablony_II

0

Po przerobieniu kodu tak jak wyżej mi mi napisałeś (mój kod wygląda dokładnie tak samo) i usunięciu tej ogólnej metody void PrintData(T& data) bo inaczej dostaję komunikat o tym że nie mogę przeładować tej funkcji

||=== Build: Debug in albums_collection (compiler: GNU GCC Compiler) ===|
C:\Users\Mateusz\Documents\Sort Tester\albums_collection\tmptree.h|142|error: explicit specialization in non-namespace scope 'class TmpTree<T>'|
C:\Users\Mateusz\Documents\Sort Tester\albums_collection\tmptree.h||In instantiation of 'class TmpTree<Album>':|
C:\Users\Mateusz\Documents\Sort Tester\albums_collection\tmptree.h|281|required from here|
C:\Users\Mateusz\Documents\Sort Tester\albums_collection\tmptree.h|142|error: 'void TmpTree<T>::PrintData(Album&) [with T = Album]' cannot be overloaded|
C:\Users\Mateusz\Documents\Sort Tester\albums_collection\tmptree.h|88|error: with 'void TmpTree<T>::PrintData(T&) [with T = Album]'|
||=== Build failed: 3 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|
 

kompilator wskazuje na linię
template<> void PrintData(Album& data);
w definicji klasy i wyrzuca
error: explicit specialization in non-namespace scope 'class TmpTree<T>'
Czy źle zrozumiałem to co mi napisałeś i po prostu muszę tutaj jeszcze coś poprawić ?

1

Prawdopodobnie robisz explicit specjalizacje funkcji w klasie. Nie można tak. Dlaczego? Cholera wie ;D

1 użytkowników online, w tym zalogowanych: 0, gości: 1