Форум программистов, компьютерный форум CyberForum.ru

Не могу определить ошибку (конкретизация шаблонной функции) - C++

Восстановить пароль Регистрация
 
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
27.02.2012, 09:39     Не могу определить ошибку (конкретизация шаблонной функции) #1
Всем привет. Есть шаблонная функция
C++
1
2
template<typename T>
void Tree<T>::inTreeHelper(const T &data, Leaf<T> *currentLeafPtr)
её нужно конкретизировать для типа char*
определяю её как
C++
1
2
template<>
void Tree<char*>::inTreeHelper(const char& *data, Leaf<char*> *currentLeafPtr)
и компилятор выдаёт ошибку

15/15-17/Tree.h|28|error: template-id ‘inTreeHelper<>’ for ‘void Tree<char*>::inTreeHelper(const char*, Leaf<char*>*)’ does not match any template declaration|

Помогите разобраться пожалуйста.

Вот полный текст программы:
Leaf.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef LEAF_H
#define LEAF_H
 
template<typename T>
class Tree;
 
template<typename T>
class Leaf
{
    friend class Tree<T>;
 
    public:
        Leaf(const T &d)
        {
            left = NULL;
            right = NULL;
            data = d;
        }
 
 
    private:
        Leaf *left;
        Leaf *right;
        T data;
};
 
#endif // LEAF_H
Tree.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#ifndef TREE_H
#define TREE_H
 
 
template<typename T>
class Tree
{
    public:
        Tree();
        ~Tree();
        void inTree(const T &);
        void printPreOrderTraversal();
        void printInOrderTraversal();
        void printPostOrderTraversal();
 
    private:
        void destructorHelper(Leaf<T> *);
        void inTreeHelper(const T &, Leaf<T> *);
        void printPreOrderTraversalHelper(Leaf<T> *);
        void printInOrderTraversalHelper(Leaf<T> *);
        void printPostOrderTraversalHelper(Leaf<T> *);
        Leaf<T> *newLeaf(const T &);
        Leaf<T> *root;
};
 
 
template<>
void Tree<char*>::inTreeHelper(const char* &data, Leaf<char*> *currentLeafPtr)
{
    if(currentLeafPtr == NULL)//создаётся корень
    {
        Leaf<char*> *ptr = newLeaf(data);
        root = ptr;
    }
   else if(strcmp(data, currentLeafPtr->data) < 0)
   {
        if(currentLeafPtr->left == NULL)
            currentLeafPtr->left = newLeaf(data);
        else
            inTreeHelper(data, currentLeafPtr->left);
   }
   else if (strcmp(data, currentLeafPtr->data) > 0)
   {
        if(currentLeafPtr->right == NULL)
            currentLeafPtr->right = newLeaf(data);
        else
            inTreeHelper(data, currentLeafPtr->right);
   }
   else
   {
       cout << "Это значение есть в дереве" << endl;
   }
}
 
 
 
template<typename T>
void Tree<T>::inTreeHelper(const T &data, Leaf<T> *currentLeafPtr)
{
    if(currentLeafPtr == NULL)//создаётся корень
    {
        Leaf<T> *ptr = newLeaf(data);
        root = ptr;
    }
   else if(data < currentLeafPtr->data)
   {
        if(currentLeafPtr->left == NULL)
            currentLeafPtr->left = newLeaf(data);
        else
            inTreeHelper(data, currentLeafPtr->left);
   }
   else if (data > currentLeafPtr->data)
   {
        if(currentLeafPtr->right == NULL)
            currentLeafPtr->right = newLeaf(data);
        else
            inTreeHelper(data, currentLeafPtr->right);
   }
   else
   {
       cout << "Это значение есть в дереве" << endl;
   }
}
 
 
template<typename T>
void Tree<T>::printPreOrderTraversalHelper(Leaf<T> *ptr)
{
    if(ptr != NULL)
    {
        if(ptr->left != NULL)
            printPreOrderTraversalHelper(ptr->left);
        cout << ptr->data << ' ';
        if(ptr->right != NULL)
            printPreOrderTraversalHelper(ptr->right);
    }
 
}
 
template<typename T>
void Tree<T>::printInOrderTraversalHelper(Leaf<T> *ptr)
{
    if(ptr != NULL)
    {
        cout << ptr->data << ' ';
        if(ptr->left != NULL)
            printInOrderTraversalHelper(ptr->left);
        if(ptr->right != NULL)
            printInOrderTraversalHelper(ptr->right);
    }
}
 
template<typename T>
void Tree<T>::printPostOrderTraversalHelper(Leaf<T> *ptr)
{
    if(ptr != NULL)
    {
        if(ptr->right != NULL)
            printPostOrderTraversalHelper(ptr->right);
        cout << ptr->data << ' ';
        if(ptr->left != NULL)
            printPostOrderTraversalHelper(ptr->left);
    }
}
 
template<typename T>
void Tree<T>::printPreOrderTraversal()
{
    printPreOrderTraversalHelper(root);
}
 
template<typename T>
void Tree<T>::printInOrderTraversal()
{
    printInOrderTraversalHelper(root);
}
 
template<typename T>
void Tree<T>::printPostOrderTraversal()
{
    printPostOrderTraversalHelper(root);
}
 
template<typename T>
void Tree<T>::destructorHelper(Leaf<T> *ptr)
{
    if(ptr != NULL)
    {
        if(ptr->left != NULL)
        {
            destructorHelper(ptr->left);
            delete ptr->left;
        }
        if(ptr->right != NULL)
        {
            destructorHelper(ptr->right);
            delete ptr->right;
        }
        if(ptr == root)
        {
            delete root;
        }
 
    }
}
 
template<typename T>
Tree<T>::Tree()
{
     root = NULL;
}
 
template<typename T>
Tree<T>::~Tree()
{
    destructorHelper(root);
}
 
template<typename T>
Leaf<T> * Tree<T>::newLeaf(const T &d)
{
    Leaf<T> *ptr = new Leaf<T>(d);
    return ptr;
}
 
template<typename T>
void Tree<T>::inTree(const T &data)
{
    inTreeHelper(data, root);
}
 
#endif // TREE_H
Main.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
#include "Leaf.h"
#include "Tree.h"
 
int main()
{
    srand(time(NULL));
    Tree<char*> t;
    char* temp;
    char str[] = "We were all feeling seedy and we were getting quite nervous about it.";
    char space[] = " ";
 
    temp = strtok(str, space);
        t.inTree(temp);
    while(temp = strtok(NULL, space))
        t.inTree(temp);
 
    t.printPreOrderTraversal();
 
    return 0;
}
Добавлено через 17 часов 48 минут
Апну тему. Помогите пожалуйста определить ошибку. :/
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.02.2012, 09:39     Не могу определить ошибку (конкретизация шаблонной функции)
Посмотрите здесь:

C++ Ошибка вызова шаблонной функции
C++ Создание шаблонной функции
C++ Не вызывается специализация шаблонной функции
C++ Тип контейнера как параметр шаблонной функции
Объявление шаблонной функции C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
27.02.2012, 10:10     Не могу определить ошибку (конкретизация шаблонной функции) #2
При специализации шаблонного класса нужно специализировать весь класс.
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
27.02.2012, 15:35  [ТС]     Не могу определить ошибку (конкретизация шаблонной функции) #3
То есть мне создать отдельный заголовочный для класса Tree<char *> и всё зарабоает?
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
27.02.2012, 16:10     Не могу определить ошибку (конкретизация шаблонной функции) #4
eaglecrazy, То есть надо специализировать весь класс для конкретного типа параметра, ага.
Luke
37 / 37 / 1
Регистрация: 21.02.2012
Сообщений: 95
27.02.2012, 16:52     Не могу определить ошибку (конкретизация шаблонной функции) #5
Цитата Сообщение от eaglecrazy Посмотреть сообщение
То есть мне создать отдельный заголовочный для класса Tree<char *> и всё зарабоает?
необязательно отдельный заголовочный. можно прям в этом специализировать

template<> class Tree<char*>;
и расписать специфичные методы для него
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
27.02.2012, 18:19     Не могу определить ошибку (конкретизация шаблонной функции) #6
можно сделать иначе.
как я понял, для разных типов понадобилась разная реализация только ф-ии inTreeHelper. причем все различие сводится к способу сравнения переменных data и currentLeafPtr->data. в таком случае нет нужды определять специализацию шаблона класса. достаточно обобщить и специализировать сравнение переменных. что все это значит? поясню на примере вашей ф-ии.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
template<typename T>
void
Tree<T>::
inTreeHelper(const T& data, Leaf<T>* currentLeafPtr)
{
    if(currentLeafPtr == NULL)//создаётся корень
    {
        Leaf<T>* ptr = newLeaf(data);
        root = ptr;
        return;
    }
    // вычисление результата сравнения
    int cmp_val = my_compare<T>(data, currentLeafPtr->data);
    if(cmp_val < 0)
    {
        if(currentLeafPtr->left == NULL)
            currentLeafPtr->left = newLeaf(data);
        else
            inTreeHelper(data, currentLeafPtr->left);
    }
    else if(cmp_val > 0)
    {
        if(currentLeafPtr->right == NULL)
            currentLeafPtr->right = newLeaf(data);
        else
            inTreeHelper(data, currentLeafPtr->right);
    }
    else
    {
        cout << "Это значение есть в дереве" << endl;
    }
}
осталось только написать шаблонную ф-ю my_compare и специализировать ее для С-строк(или еще чего-нибудь при надобности). как пример, она может выглядеть так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename T>
int
my_compare(T a, T b)
{
    return a < b ? -1 : a == b ? 0 : 1;
}
 
template<>
int
my_compare(char* a, char* b)
{
    return strcmp(a, b);
}
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
27.02.2012, 23:12  [ТС]     Не могу определить ошибку (конкретизация шаблонной функции) #7
Всем спасибо! К сожалению сегодня времени нет проверить. Завтра вечером попробую.
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
28.02.2012, 23:26  [ТС]     Не могу определить ошибку (конкретизация шаблонной функции) #8
Вот я и добрался до компьютера. Прочитав пост retmas решил выделить функцию для сравнения. Но решил сделать функцию - член класса, а не просто шаблонную, ибо хочу разобраться в данном вопросе. Сделал две функции для классов Tree<T> и Tree<char*> и определил класс Tree<char*> Вот что вышло:

Класс Tree<char*>
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template<>
class Tree<char*>
{
        public:
        Tree();
        ~Tree();
        void inTree(char* &);
        void printPreOrderTraversal();
        void printInOrderTraversal();
        void printPostOrderTraversal();
 
    private:
        void destructorHelper(Leaf<char*> *);
        void inTreeHelper(const char* &, Leaf<char*> *);
        void printPreOrderTraversalHelper(Leaf<char*> *);
        void printInOrderTraversalHelper(Leaf<char*> *);
        void printPostOrderTraversalHelper(Leaf<char*> *);
        int myCompare(const char* &, const char* &);
        Leaf<char*> *newLeaf(const char* &);
        Leaf<char*> *root;
};
Сравнение для Tree<T>:
C++
1
2
3
4
5
6
7
8
9
10
template<typename T>
int Tree<T>::myCompare(const T &a, const T &b)
{
    if (a < b)
        return -1;
    else if (a > b)
        return 1;
    else
        return 0;
}
Сравнение для Tree<char*>:
template<>
int Tree<char*>::myCompare(const char* &a, const char* &b)
{
if(strcmp(a, b) < 0)
return -1;
else if(strcmp(a, b) > 0)
return 1;
else
return 0;
}

В итоге получается та же ошибка:
C++
1
 15/15-17/Tree.h|205|error: template-id ‘myCompare<>forint Tree<char*>::myCompare(const char*&, const char*&)’ does not match any template declaration|
Что я на этот раз неправильно делаю?
И вот ещё вопрос, почему когда я делаю специализированную функцию для классов Tree<char> или Tree<int> без описания специального класса, всё работает, и только когда нужно сделать для типа Tree<char*> не хочет?
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
29.02.2012, 00:55     Не могу определить ошибку (конкретизация шаблонной функции) #9
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
 
template <typename T>
class X
{
public:
  void f(const T& a, const T& b);
};
 
template <typename T>
void X<T>::f(const T& a, const T& b)
{
  std::cout << "common" << std::endl;
}
 
template <>
class X<char>
{
public:
  void f(const char& a, const char& b);
};
 
void X<char>::f(const char& a, const char& b)
{
  std::cout << "char" << std::endl;
}
 
int main()
{
  int i = 0;
  char c = 0;
 
  X<int> xInt;
  xInt.f(i, i);
  X<char> xChar;
  xChar.f(c, c);
 
  return 0;
}
Добавлено через 13 минут
Еще такая деталь:
при Т == char* следующие записи - не одно и то же.
1) const T& arg
2) const char*& arg
В первом случае агрумент имеет тип: константная ссылка на неконстантный указатель. т.е. аргумент менять нельзя, но можно изменять то, на что он указывает.
Во втором случае агрумент имеет тип: ссылка на константный указатель. т.е. агумент менять можно, но нельзя менять то, на что он указыает.
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
29.02.2012, 20:36  [ТС]     Не могу определить ошибку (конкретизация шаблонной функции) #10
DU, скажите, а можно ли ваш пример что бы с char* работал, а не с char. Так как специализированная функция для char у меня тоже без проблем работает. Буду весьма благодарен.

Я вообще правильно передаю в функцию указатель на char по ссылке?

Добавлено через 16 минут
И нужно ли если описывать специализированный класс для char*, описывать в классе все функции и заново определять все функции для этого класса? Или достаточно только myCompare?
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
29.02.2012, 22:21     Не могу определить ошибку (конкретизация шаблонной функции) #11
... а можно ли ваш пример что бы с char* работал, а не с char
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
 
template <typename T>
class X
{
public:
  void f(const T& a, const T& b);
};
 
template <typename T>
void X<T>::f(const T& a, const T& b)
{
  std::cout << "common" << std::endl;
}
 
template <>
class X<char*>
{
public:
  // Эта сигнатура отличается от сигнатуры обобщенного варианта. Это я описал уже.
  void f(const char* a, const char* b);
};
 
void X<char*>::f(const char* a, const char* b)
{
  std::cout << "char*" << std::endl;
}
 
int main()
{
  int i = 0;
  char* c = 0;
 
  X<int> xInt;
  xInt.f(i, i);
  X<char*> xChar;
  xChar.f(c, c);
 
  return 0;
}
И нужно ли если описывать специализированный класс для char*, описывать в классе все функции и заново определять все функции для этого класса? Или достаточно только myCompare?
Да, нужно будет все функции заново сделать. Но если в вашем случае для указателей на чары специфичный только один метод, а все остальные обощие, то так делать не удобно. Лучше воспользоваться классом стратегией для сравнения. Это может быть как внутренний класс, невидимый ни для кого, так и внешний. Если внешний, то он может как передаваться в шаблон, так и не передаваться. Последний случай самый простой и выглядеть это будет примерно так:

Вместо переписывание всех функций заново, достаточно кастомизировать лишь одну функцию сравнения. И кастомизация эта будет в отдельном шаблонном классе, который можно для чаров как раз и специализируется. Класс удобен тем, что в него можно добавить кастомизацию другой еще одной функции, если же этого не надо, то достаточно будет одной шаблонной функции для общего случая и семейства нешаблонных функций для частных случаев.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
 
template <typename T>
struct XTraits
{
  typedef T Type;
 
  static void Compare(const Type& a, const Type& b)
  {
    std::cout << "Common compare" << std::endl;
  }
};
 
template <>
struct XTraits<char*>
{
  typedef char* Type;
 
  static void Compare(const Type& a, const Type& b)
  {
    std::cout << "char* compare" << std::endl;
  }
};
 
template <typename T>
class X
{
public:
  //... Тут куча обобщенных функций
 
  // A вот эта специальная:
  void Compare(const T& a, const T& b)
  {
    XTraits<T>::Compare(a, b);
  }
};
 
int main()
{
  int i = 0;
  char* c = 0;
 
  X<int> xInt;
  xInt.Compare(i, i);
  X<char*> xChar;
  xChar.Compare(c, c);
 
  return 0;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.02.2012, 23:54     Не могу определить ошибку (конкретизация шаблонной функции)
Еще ссылки по теме:

Присваивание по ссылке в шаблонной функции C++
C++ Вызов шаблонной функции
C++ Экспорт шаблонной функции из DLL

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
29.02.2012, 23:54  [ТС]     Не могу определить ошибку (конкретизация шаблонной функции) #12
Господа, в другом месте мне дали ответ с примером и я всё понял. Надо было вот так,

C++
1
2
3
4
5
6
7
8
9
10
11
template<>
int Tree<char*>::myCompare(char* const &a, char* const &b)
{
    cout << "compare for char*\n";
    if(strcmp(a, b) < 0)
        return -1;
    else if(strcmp(a, b) > 0)
        return 1;
    else
        return 0;
}
А описывать специализированный класс как бы и не зачем...
Yandex
Объявления
29.02.2012, 23:54     Не могу определить ошибку (конкретизация шаблонной функции)
Ответ Создать тему
Опции темы

Текущее время: 00:58. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru