Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вопрос по шаблонам

7.1K
27 августа 2004 года
krl
11 / / 28.07.2004
Я создаю шаблонный класс, в нем еще один класс (не шаблоннный), однако при попытке объявить оператор для второго класса, BC++B6 пишет, что 'operator==' not implemented in type 'A<int>::B' for arguments of same type
Код:
template <class T> class A
{  public:
      class B { };
};
template <class T> bool operator ==(A<T>::B, A<T>::B) { return 1; }

int main()
{
   A<int>::B a, b;
   a == b;
}

Почему этот код при компиляции выдает вышеуказанную ошибку, вроде бы оператор объявлен правильно для данного случая?
2.0K
27 августа 2004 года
Fazil6
126 / / 17.12.2003
Цитата:
Originally posted by krl
Я создаю шаблонный класс, в нем еще один класс (не шаблоннный), однако при попытке объявить оператор для второго класса, BC++B6 пишет, что 'operator==' not implemented in type 'A<int>::B' for arguments of same type
Код:
template <class T> class A
{  public:
      class B { };
};
template <class T> bool operator ==(A<T>::B, A<T>::B) { return 1; }

int main()
{
   A<int>::B a, b;
   a == b;
}

Почему этот код при компиляции выдает вышеуказанную ошибку, вроде бы оператор объявлен правильно для данного случая?



Круто. А что за операция

Цитата:
a == b;



где объявление == в классе?

7.1K
27 августа 2004 года
krl
11 / / 28.07.2004
В этом-то и дело, что хотелось объявить вне класса.
Можно же объявить
 
Код:
template <class T> bool operator ==(A<T>, A<T>) { return 1; }
вне класса A. Просто непонятно, как сделать то же самое для класса B.
Если написать
 
Код:
bool operator ==(A<int>::B, A<int>::B) { return 1; }
то все работает, но как быть с шаблонами?
В принципе, объявление внутри класса допустимо, но хочется понять, что в моем варианте неправильно.
3
27 августа 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by krl
В принципе, объявление внутри класса допустимо, но хочется понять, что в моем варианте неправильно.



Все у тебя правильно.
У меня все нормально компилируется (VC++ 7.0) и выполняется. Думаю, это баг компилятора.

P.S. Ща буду занудствовать: если у тебя возвращаемое значение объявлено, как bool, то и возвращай bool (true, false), а не целочисленное значение (1).

2.0K
27 августа 2004 года
Fazil6
126 / / 17.12.2003
Цитата:
Originally posted by krl
В этом-то и дело, что хотелось объявить вне класса.
Можно же объявить
 
Код:
template <class T> bool operator ==(A<T>, A<T>) { return 1; }
вне класса A. Просто непонятно, как сделать то же самое для класса B.
Если написать
 
Код:
bool operator ==(A<int>::B, A<int>::B) { return 1; }
то все работает, но как быть с шаблонами?
В принципе, объявление внутри класса допустимо, но хочется понять, что в моем варианте неправильно.




Вопросы чистой религии.
Мне кажется потому, что ищет шаблон для A<int>::B, а у тебя все таки для int.

1
27 августа 2004 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by krl
В этом-то и дело, что хотелось объявить вне класса.
Можно же объявить
 
Код:
template <class T> bool operator ==(A<T>, A<T>) { return 1; }
вне класса A. Просто непонятно, как сделать то же самое для класса B.
Если написать
 
Код:
bool operator ==(A<int>::B, A<int>::B) { return 1; }
то все работает, но как быть с шаблонами?
В принципе, объявление внутри класса допустимо, но хочется понять, что в моем варианте неправильно.


 
Код:
template <class T> T operator ==(A<T>::B a, A<T>::B b){return 1;}
2.0K
27 августа 2004 года
Fazil6
126 / / 17.12.2003
Цитата:
Originally posted by Green


Все у тебя правильно.
У меня все нормально компилируется (VC++ 7.0) и выполняется. Думаю, это баг компилятора.



мне кажется, что надо так

template <class T> bool operator ==(T, T ) { return 1; }

Выглядит правильно, и борланд заткнулся

3
27 августа 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Fazil6

мне кажется, что надо так

template <class T> bool operator ==(T, T ) { return 1; }

Выглядит правильно, и борланд заткнулся



:)
Тогда это будет работать для всех классов (типов), а не только для A<T>::B.
Т.е.

 
Код:
class C
{
public:
    C(int val) :val(val) {}
    int val;
};

C(1) == C(2); // Тоже вернет true !!!


Цитата:
Originally posted by kot_

template <class T> T operator ==(A<T>::B a, A<T>::B b){return 1;}



Оператор должен вернуть bool, а не T

krl, настаиваю на том, что это ошибка компилятора.
Кстати, я бы использовал передачу аргументов по ссылке, т.е.

template <class T>
bool operator ==(A<T>::B&, A<T>::B&)
{ return true; }

2.0K
27 августа 2004 года
Fazil6
126 / / 17.12.2003
Цитата:
Originally posted by Green


:)
Тогда это будет работать для всех классов (типов), а не только для A<T>::B.



Конечно. Но я думаю, что мы чисто теоретический код расматриваем, т.к. a == b тоже смысла не имеет. Я просто думаю, что в данном случае компилятор хочет, чтобы было именно так

template <class T> bool operator ==(T, T ) { return 1; }

и ни как по другому. Так что надо подход менять. Ну или компилятор :)

7.1K
27 августа 2004 года
krl
11 / / 28.07.2004
Цитата:
Originally posted by Green
Кстати, я бы использовал передачу аргументов по ссылке

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

Цитата:
Originally posted by Fazil6
Так что надо подход менять. Ну или компилятор

Так вот и непонятно, на что менять подход. Работать-то хоть как-то надо. Опять же, можно засунуть оператор и в сам класс, но IMHO это неэлегантно и неправильно (т.к. по смыслу задачи оператору доступ к самим элементам класса не обязателен, даже в std::vector операторы сравнения вынесены из самого класса).
С компилятором понятнее, но сложнее (намного).

Вроде как нашел один способ:

Код:
template <class T> class C { };
template <class T> class A
{  public:
      typedef C<T> B;
};
template <class T> bool operator ==(C<T>, C<T>) { return 1; }

int main()
{
   A<int>::B a, b;
   a == b;
}
По правде говоря, мне этот workaround не так уж и нравится, но похоже, что другого варианта нет.
P.S. Идея пришла от просмотров исходников std::list, там тоже iterator объявлен через typedef. Раз уж там так сделано, наверное, это единственный вариант.
1
27 августа 2004 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by Green


:)
Тогда это будет работать для всех классов (типов), а не только для A<T>::B.
Т.е.
 
Код:
class C
{
public:
    C(int val) :val(val) {}
    int val;
};

C(1) == C(2); // Тоже вернет true !!!




Оператор должен вернуть bool, а не T

krl, настаиваю на том, что это ошибка компилятора.
Кстати, я бы использовал передачу аргументов по ссылке, т.е.

template <class T>
bool operator ==(A<T>::B&, A<T>::B&)
{ return true; }


Компилятор здесь не причем. Ошибка, и моя в том числе в том, что при обявлении шаблона нужно использовать:

 
Код:
template <class T> bool operator ==(T, T )

на то это и шаблон.:)
То что компилятор мелкомягких пытается править ошибки программиста - к С++ и шаблонам никакого отношения не имеет.
Тут вопрос уже в другом - на сколько рационально и необходимо определять шаблон для проверки на равенство объектов. Не проще ли определить его в классе? Кроме распухания кода польза сомнительная.
7.1K
27 августа 2004 года
krl
11 / / 28.07.2004
Цитата:
Originally posted by kot_

Тут вопрос уже в другом - на сколько рационально и необходимо определять шаблон для проверки на равенство объектов. Не проще ли определить его в классе? Кроме распухания кода польза сомнительная.


Цитата:
The C++ Programming Language, Bjarne Stroustup, 11.13 Advice

[6]Prefer member functions over nonmembers for operations that need access to the representation.
[7]Prefer nonmember functions over members for operations that do not need access to the representation
11.5.2
if implicit type conversion is desired for all operands of an operation, the function implementing it must be a nonmember function taking a const reference or a non-reference argument.

По-моему это как раз относится к моему случаю.

3
27 августа 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by kot_

Компилятор здесь не причем. Ошибка, и моя в том числе в том, что при обявлении шаблона нужно использовать:
 
Код:
template <class T> bool operator ==(T, T )

на то это и шаблон.:)



Неа... Ты не прав.
В коде действительно одна ошибка, которую VC++7.0 пытается править, а VC++7.1 уже сигнализирует. И ошибка эта в отсутствии typename:

template <class T>
bool operator ==(typename A<T>::B, typename A<T>::B);

7.1K
27 августа 2004 года
krl
11 / / 28.07.2004
Цитата:
Originally posted by Green

В коде действительно одна ошибка, которую VC++7.0 пытается править, а VC++7.1 уже сигнализирует. И ошибка эта в отсутствии typename:

template <class T>
bool operator ==(typename A<T>::B, typename A<T>::B);

Даже если добавить typename, все равно не работает

1
27 августа 2004 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by krl
Даже если добавить typename, все равно не работает


typename = class
По стандарту рекомендуется использовать первое - исходя из того что в шаблон могут загружатся типы данных, классами не являющиеся. Но это не ошибка, по меньшей мере пока. Допустимо использовать и typename и class.Другое дело что список параметров должен соответствовать списку параметров шаблона. То есть ошибка объявлять шаблон вот так:

 
Код:
template <class T> bool operator ==(A<T>::B a, A<T>::B b){return 1;}

В качестве параметра шаблона мы передаем Т а в список параметров функции предаем что? В таком случае мы должны явно инстанцировать шаблон для ...для...для чего?...:)
Скорее всего VC в данном случае просто инстанцирует это ввиде
 
Код:
typedef A<int> T;
template <typename T::B> bool operator ==(typename T::B a, typename T::B b){return 1;}

не особо заботясь, что на самом деле имел ввиду разработчик. А что имел он ввиду он помоему и сам не догадывается...:)
Ну а если серьезно, то фактически вырождается все это в ту же форму template<typename T>bool operator==(T,T).
Все это пока теоретически - будет время проверьте.
3
27 августа 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by kot_

typename = class
По стандарту рекомендуется использовать первое - исходя из того что в шаблон могут загружатся типы данных, классами не являющиеся.


Это ты вообще не из той оперы взял.

Цитата:
Originally posted by kot_

Другое дело что список параметров должен соответствовать списку параметров шаблона.


А вот это уже полная ерунда.
Смотрим стандарт!

Цитата:
Originally posted by kot_

То есть ошибка объявлять шаблон вот так:
 
Код:
template <class T> bool operator ==(A<T>::B a, A<T>::B b){return 1;}

В качестве параметра шаблона мы передаем Т а в список параметров функции предаем что? В таком случае мы должны явно инстанцировать шаблон для ...для...для чего?...:)
Скорее всего VC в данном случае просто инстанцирует это ввиде
 
Код:
typedef A<int> T;
template <typename T::B> bool operator ==(typename T::B a, typename T::B b){return 1;}

не особо заботясь, что на самом деле имел ввиду разработчик. А что имел он ввиду он помоему и сам не догадывается...:)
Ну а если серьезно, то фактически вырождается все это в ту же форму template<typename T>bool operator==(T,T).


А это уже скороспелые неверные выводы и обилие эмоций.

1
28 августа 2004 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by Green

Это ты вообще не из той оперы взял.


А вот это уже полная ерунда.
Смотрим стандарт!


А это уже скороспелые неверные выводы и обилие эмоций.


Ну смотрим стандарт:

Цитата:
Originally posted by Стандарт


1 Given two function templates, whether one is more specialized than
another can be determined by transforming each template in turn and
using argument deduction (_temp.deduct_) to compare it to the other.

2 The transformation used is:

--For each type template parameter, synthesize a unique type and sub-
stitute that for each occurrence of that parameter in the function
parameter list.

--For each non-type template parameter, synthesize a unique value of
the appropriate type and substitute that for each occurrence of that
parameter in the function parameter list.

3 Using the transformed function parameter list, perform argument deduc-
tion against the other function template. The transformed template is
at least as specialized as the other if, and only if, the deduction
succeeds and the deduced parameter types are an exact match (so the
deduction does not rely on implicit conversions).

4 A template is more specialized than another if, and only if, it is at
least as specialized as the other template and that template is not at
least as specialized as the first. [Example:
template<class T> struct A { A(); };

template<class T> void f(T);
template<class T> void f(T*);
template<class T> void f(const T*);

template<class T> void g(T);
template<class T> void g(T&);

template<class T> void h(const T&);
template<class T> void h(A<T>&);


В чем мои выводы скороспелы, неверны и наполнены эмоциями? Может с точки зрения теории они и не идеальны, но:

Цитата:
Originally posted by Страуструп


"Существенным моментом здесь является возможность выведения (deduction)типа аргументов шаблона функции по типам аргументов при ее вызове.
Компилятор может вывести аргументы, как являющиеся типами, так и обычные, при условии, что список аргументов функции однозначно индентифицирует набор аргументов цаблона..."


третья редакция стр.385.

3
28 августа 2004 года
Green
4.8K / / 20.01.2000
Ты видишь разницу между Страуструпом:
Цитата:
при условии, что список аргументов функции однозначно индентифицирует набор аргументов шаблона


и твоим:

Цитата:
Другое дело что список параметров должен соответствовать списку параметров шаблона



Однозначно идентифицирует - это не тоже самое, что соответствует (в твоем понимании "совпадает").
Для наглядности:
template<class T> void func(A<T>); // однозначно идентифицирует

template<class T> void func(A<T>::B); // однозначно идентифицирует

template<class T> void func(T); // совпадает

Так где в стандарте сказано, что тип аргумента должен совпадать с параметром шаблона?

Я не понимаю всего этого флейма.
Я привожу пример из стандарта:
template<class T> void sort(Array<T>&);

Ты сам приводишь пример из стандарта:
template<class T> void h(A<T>&);

И при этом утверждаешь, что это неправильно?
Что тип аргумента функции должен быть точно таким же как параметр шаблона.

Получается что и STL, и Boost, и Loki не должны работать?

1
28 августа 2004 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by Green

настаиваю на том, что это ошибка компилятора.


Я утверждаю что форма записи:
template<class T> void func(A<T>::B);
не верна и ошибки компилятора здесь ни причем.
Параметр типа шаблона определен один, в параметры функции передается другой тип.
Не одно и тоже -
template<class T> void func(A<T>::B&);
и
template<class T> void func(A<T>&);
Если бы можно было однозначно идентифицировать при этом тип объекта - не было бы проблем.
Или второй вариант - явно инстанцировать шаблон для конкретного типа данных.
К сожалению, у меня нет возможности сейчас проверить как и что будет работать, поэтому в отличии от тебя я не утверждаю что мои слова - истина в последней инстанции, и не ищу ошибки компиляторов.
Кстати, по той же причине не могу покопаться в STL - в каких шаблонах функций используется ТАКОЕ определение? Я не помню. Но я могу и ошибаться.

3
28 августа 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by kot_

Я утверждаю что форма записи:
template<class T> void func(A<T>::B);
не верна и ошибки компилятора здесь ни причем.
Параметр типа шаблона определен один, в параметры функции передается другой тип.
Не одно и тоже -
template<class T> void func(A<T>::B&);
и
template<class T> void func(A<T>&);

К сожалению, у меня нет возможности сейчас проверить как и что будет работать, поэтому в отличии от тебя я не утверждаю что мои слова - истина в последней инстанции, и не ищу ошибки компиляторов.
Кстати, по той же причине не могу покопаться в STL - в каких шаблонах функций используется ТАКОЕ определение? Я не помню. Но я могу и ошибаться.



Ну я тоже ничего не констатирую, просто стараюсь отстоять свою точку зрения.
Кстати, она несколько расшаталась... :D
Пункт 14.8.2.10 внес сомнения в мою позицию:

 
Код:
template<int i, typename T>
T deduce(A<T>::X x,     // T is not deduced here
         T       t,     // but T is deduced here
         B::Y y);    // i is not deduced here
1
28 августа 2004 года
kot_
7.3K / / 20.01.2000
:) Зато хорошо прошлись по теории шаблонов.
Кстати, пока мы спорили, никто не догадался попробовать:
template<class T> void func(A<T>::B*);?
Ведь в таком случае тип определен, проблемы конструирования объекта становятся задачей программиста и компилятор спокойно это съест. Проблемы будут только если функция возвращает значение (я имею ввиду здесь только проблемы компиляции, остальные не трогаем)Или я ошибаюсь?
7.1K
28 августа 2004 года
krl
11 / / 28.07.2004
Кстати, у Страуструпа написано, какие правила ипользуются при выведении типов параметров функций (C.13.4) Есть только class_template_name<T>, class_template_name, где T - type, I - non-type. Варианта class_template_name<T>::* там нет.
Наверное, проще всего объявить тип через typedef внутри класса, и сам класс описать отдельно.
Не понимаю, какие проблемы могут быть, если такая функция возвращает значение? И неужели удобно так работать с указателями?
1
30 августа 2004 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by krl
Кстати, у Страуструпа написано, какие правила ипользуются при выведении типов параметров функций (C.13.4) Есть только class_template_name<T>, class_template_name, где T - type, I - non-type. Варианта class_template_name<T>::* там нет.
Наверное, проще всего объявить тип через typedef внутри класса, и сам класс описать отдельно.
Не понимаю, какие проблемы могут быть, если такая функция возвращает значение? И неужели удобно так работать с указателями?


Ну не не знаю, думаю в целом ряде библиотек ты сможешь найти конструкции типа:

 
Код:
template<class T> void somefunct(Array<T>::iterator* iter,...);

использование параметров, не являющихся типами - т.е. - целочисленный, тип указателя и ссылочный - допустимо. Если для тебя уж так значимо использование шаблонной функции для проверки полей класса - стоит попробовать.По поводу проблем с возвращаемым значением - честно не помню...:)
Использование указателей - рекомендуется если твоя система не критична по пямяти и быстродействию. Так как при использовании указателей происходит выделение памяти из кучи, т.е. в конкретном месте программы размер объекта может быть не известен, для системы в которой эта память мала, выделение может закончится крахом. Разыменовывание указателя -> так же может быть операцией с высокими накладными расходами. С другой стороны - использование указателей может сделать программу гораздо более эффективной - особенно если размер кучи достаточно велик. Все завистит от того какие задачи перед тобой стоят. Но практически со сто процентной уверенностью можно сказать - там где используются шаблоны, имеет смысл использовать указатели. С умом.:D :D
3
30 августа 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by kot_

Ну не не знаю, думаю в целом ряде библиотек ты сможешь найти конструкции типа:
 
Код:
template<class T> void somefunct(Array<T>::iterator* iter,...);

использование параметров, не являющихся типами - т.е. - целочисленный, тип указателя и ссылочный - допустимо.


Посмотрел имеющиеся библиотеки (STL, STLPort, Loki, Boost-а к сожалению на этой машине нет). Нигде не нашел такой конструкции, за исключением методов-членов, но они не в счет.
Можешь показать места, где такое встречается. Может, я плохо искал... :о\

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

Кстати, ссылка на Comeau онлайн компилятор, утверждают, что полностью поддерживает стандарт:
http://www.comeaucomputing.com/tryitout/

1
30 августа 2004 года
kot_
7.3K / / 20.01.2000
Экскуз, добрел до рабочего места.
1. Ключевое слово typename
"Это ключевое слово введено в язык в процессе стандартизации С++ для указания того, что идентификатор в шаблоне является типом. Рассмотри следующий пример:
 
Код:
template <typename T> class MyClass{
  typename T::SubType* ptr;

В этом примере второе ключевое слово typename используется для пояснения, что SubType является типом, определенным внутри класса Т. Таким образом, ptr является указателем на T::SubType. Без такого указания с помощью typename идентификатор SubType интерпретировался как статический член класса, т.е. как конкретная переменная или объект. В результате выражение
T::SubType *ptr представляло бы умножение статического члена класса SubType на объект ptr..."(Вандервурд Д. "Шаблоны С++. Справочник разработчика", гл. 5.1 )
2. По поводу использования в шаблонах функций указателей на члены классов-шаблонов - мое предположение было неверным. По крайней мере ни где в стандартной библиотеке я не нашел что либо похожего, при попытке создать что либо таким образом - компилятор выдает ошибку. Как говорится - не в сказке живем...:)
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог