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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
#1

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

27.02.2012, 09:39. Просмотров 1042. Ответов 11
Метки нет (Все метки)

Всем привет. Есть шаблонная функция
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 минут
Апну тему. Помогите пожалуйста определить ошибку. :/
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.02.2012, 09:39
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Не могу определить ошибку (конкретизация шаблонной функции) (C++):

Как определить тип возвращаемого значения шаблонной функции по типу итератора (не auto)? - C++
Здравствуйте. Есть шаблонная функция (например, суммирования). Входные значения два итератора -- начало конец. template &lt;typename...

Создание шаблонной функции - C++
Создать шаблонную функцию, изменяющий порядок элементов таким образом: первая половина списка смещается в конец, а вторая в начало. К...

Объявление шаблонной функции - C++
Здравствуйте, встретил в учебнике это: template &lt;typename Type, int size&gt; Type min( Type (&amp;r_array) ) { //... }

Вызов шаблонной функции - C++
Что я делаю не так? есть функция: template &lt;class T&gt; T rFF(string input_file) { string tmp; ifstream file(input_file); file...

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

Ошибка вызова шаблонной функции - C++ - C++
Читаю Прата, остановился на таком задании: Напишите функцию с интерфейсом в старом стиле, которая имеет следующий прототип: int...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
ForEveR
В астрале
Эксперт С++
7972 / 4734 / 321
Регистрация: 24.06.2010
Сообщений: 10,541
Завершенные тесты: 3
27.02.2012, 10:10 #2
При специализации шаблонного класса нужно специализировать весь класс.
0
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
27.02.2012, 15:35  [ТС] #3
То есть мне создать отдельный заголовочный для класса Tree<char *> и всё зарабоает?
0
ForEveR
В астрале
Эксперт С++
7972 / 4734 / 321
Регистрация: 24.06.2010
Сообщений: 10,541
Завершенные тесты: 3
27.02.2012, 16:10 #4
eaglecrazy, То есть надо специализировать весь класс для конкретного типа параметра, ага.
0
Luke
39 / 39 / 1
Регистрация: 21.02.2012
Сообщений: 95
27.02.2012, 16:52 #5
Цитата Сообщение от eaglecrazy Посмотреть сообщение
То есть мне создать отдельный заголовочный для класса Tree<char *> и всё зарабоает?
необязательно отдельный заголовочный. можно прям в этом специализировать

template<> class Tree<char*>;
и расписать специфичные методы для него
0
retmas
Жарю без масла
859 / 741 / 164
Регистрация: 13.01.2012
Сообщений: 1,694
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);
}
0
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
27.02.2012, 23:12  [ТС] #7
Всем спасибо! К сожалению сегодня времени нет проверить. Завтра вечером попробую.
0
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*> не хочет?
0
DU
1483 / 1059 / 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
В первом случае агрумент имеет тип: константная ссылка на неконстантный указатель. т.е. аргумент менять нельзя, но можно изменять то, на что он указывает.
Во втором случае агрумент имеет тип: ссылка на константный указатель. т.е. агумент менять можно, но нельзя менять то, на что он указыает.
0
eaglecrazy
1 / 1 / 0
Регистрация: 06.02.2012
Сообщений: 31
29.02.2012, 20:36  [ТС] #10
DU, скажите, а можно ли ваш пример что бы с char* работал, а не с char. Так как специализированная функция для char у меня тоже без проблем работает. Буду весьма благодарен.

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

Добавлено через 16 минут
И нужно ли если описывать специализированный класс для char*, описывать в классе все функции и заново определять все функции для этого класса? Или достаточно только myCompare?
0
DU
1483 / 1059 / 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;
}
0
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;
}
А описывать специализированный класс как бы и не зачем...
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.02.2012, 23:54
Привет! Вот еще темы с ответами:

Экспорт шаблонной функции из DLL - C++
Привет! В DLL есть класс и глобальная шаблонная функция, для получения интерфейса этого класса при динамическом подключение DLL: ...

Ошибка вызова шаблонной функции - C++
Вообщем у меня вопрос такой: Использую MVS 2010. Пишу шаблон функции для поиска максимального из двух чисел: template &lt;class T&gt; T...

Аргумент в виде шаблонной функции - C++
void Function(любая_функция_с_одним_параметром){} Как при помощи шаблона всунуть в аргумент функции, любую функцию с одним параметром,...

Экспортирование шаблонной функции из dll - C++
Использую mvs 2013 Весь вечер курил сайт microsoft по шаблонам и dll, никакого упоминания об экспортировании шаблонной функции из dll, не...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
29.02.2012, 23:54
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru