Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #120 : 13-04-2009 09:34 » |
|
Алгоритм sort реализован ещё в C десятки лет назад. Функция qsort определена в stdlib.h void qsort(void *base, size_t nelem, size_t width, int (*fcmp)(const void *, const void *)); Пример из help к Turbo C++ 3.0: #include <stdio.h> #include <stdlib.h> #include <string.h>
int sort_function(const void *a, const void *b);
char list[5][4] = { "cat", "car", "cab", "cap", "can" };
int main(void) { int x; qsort((void *)list, 5, sizeof(list[0]), sort_function); for (x = 0; x < 5; x++) printf("%s\n", list[x]); return 0; }
int sort_function(const void *a, const void *b) { return( strcmp((char *)a,(char *)b) ); } Функция сравнения должна возвращать отрицательное число, 0 или положительное число для a<b, a=b и a>b соответственно.
|
|
« Последнее редактирование: 13-04-2009 09:38 от dimka »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Вад
|
|
« Ответ #121 : 13-04-2009 10:19 » |
|
Алексей1153++, проще всего определить независимую функцию (как вариант: статический метод класса) сравнения двух указателей, которая сравнивает то, на что они указывают. Можно отдельным функтором оформить. В качестве параметра передавать, соответственно, функцию или экземпляр функтора. Не думаю, что переопределение операции сравнения для указателей является лучшим вариантом. В общем, я бы сделал что-то вроде: template<typename Type_> bool compare_val_by_ptr( Type_* left, Type_* right ) { return (*left) < (*right); }
//... std::vector<int*> vec; std::sort(vec.begin(), vec.end(), compare_val_by_ptr<int>);
(если подумать, то, наверное, можно и покрасивее)
|
|
« Последнее редактирование: 13-04-2009 10:37 от Вад »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #122 : 13-04-2009 11:03 » |
|
Вад, ну я для указателей и не переопределял, а только для класса myDWORDp )
-------- я там в структуре подправил, не то имел в виду )
|
|
« Последнее редактирование: 13-04-2009 11:38 от Алексей1153++ »
|
Записан
|
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #124 : 25-09-2009 10:49 » |
|
как сделать шаблон для генерации типов, инкапсулирующих "простые" типы ? нужно, чтобы получилось нечто вроде (но это спотыкается на объявлении переменных) template<class T,T defaultVal,const char* TXTname> class X { T m_par;
public:
X() { m_par=defaultVal; }
const T& (operator=) (const T& src) { m_par=src; return m_par; }
operator T&() { return m_par; }
const char* GetTextName() { return TXTname; } };
//объявление X<int,0,"параметр1"> m_1; X<CString,"0","параметр2"> m_2; X<BYTE,0,"параметр3"> m_3;
//работа с объектом должна происходить точно так же, как будто работаем просто с мембером m_par, например : void F() { CString t; t=m_2; m_2=t; m_2="1111111"; }
компилятор пишет недопустимое выражение в качестве аргумента шаблона для 'TXTname'
|
|
« Последнее редактирование: 25-09-2009 11:29 от Алексей1153++ »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #125 : 25-09-2009 14:13 » |
|
Параметры шаблона должны быть константами, не могущими изменяться в runtime - аналог макросов, а ты объявляешь указатель char *, для представления которого нужна переменная с хранящимся внутри неё адресом. Кроме того, твой объект не умеет работать с другими такими объектами. Например, ещё надо добавить что-то типа: const X<T>& (operator=) (const X<T>& src) { m_par=src; return m_par; } Или я не понимаю, как этим пользоваться "прозрачно".
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #126 : 25-09-2009 14:32 » |
|
как таки задать строку ещё на этапе компиляции ? Или только через конструктор придётся ?
А про const X<T>& - это точно , не подумал )) Но если бы в коде встретилась необходимость, дошло бы
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #127 : 25-09-2009 18:29 » |
|
Народ на других форумах пишет, что можно передавать только такие строки, которые объявлены в глобальных переменных. Типа template<const char *s> class X {/*...*/};
/* Строковая константа обязательно в глобальной области видимости (или namespace), которая не удаляется при завершении какой-нибудь функций (даже main). */ char s[] = "Test";
int main() { X<s> x; }
|
|
« Последнее редактирование: 25-09-2009 18:33 от Dimka »
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #128 : 26-09-2009 03:12 » |
|
попробую. Хотя мне это не нравится, лучше затолкну название через конструктор
Про глобальность тут не совсем всё ясно, дело в том, что строки вида "строка" и так являются глобальными константами, хотя и и сограниченной видимостью. Специально проверял: если в совершенно различных местах программы встречается выражение "текст" , и текст одинаковый, то указатель выходит одинаковый. То есть компилятор размещает в данных всего одну константную строку и использует указатель при каждом удобном случае.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #129 : 28-09-2009 10:29 » |
|
а возможно ли сделать в шаблоне условную компиляцию по типу T ? Навроде
if(тип T == CString) { T=T.Left(10); } else { }
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #130 : 28-09-2009 10:48 » |
|
Ну, скажем, у Александреску есть такой вариант, построенный на специализации шаблона: template <int v> struct IntToType { enum {value = v }; };
template <class T, class U> struct SameType { enum { result = false }; };
template <class T> struct SameType<T, T> { enum {result = true }; };
// ... void Foo(Type& T, IntToType<true>) { T=T.Left(10); }
void Foo(Type&, IntToType<false>) { }
void Foo(Type& T) { Foo(T, IntToType<SameType<Type, CString>::result>()); }
Сделал на коленке, не проверял работоспособность Но принцип примерно такой
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #131 : 28-09-2009 11:04 » |
|
Алексей1153++, возможно читаем Вандервуда 15.2 Type Functions =============== 15.2.2 Determining Class Types With the following type function we can determine whether a type is a class type: // traits/isclasst.hpp
template<typename T> class IsClassT { private: typedef char One; typedef struct { char a[2]; } Two; template<typename C> static One test(int C::*); template<typename C> static Two test(…); public: enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 }; enum { No = !Yes }; };
This template uses the SFINAE (substitution-failure-is-not-an-error) principle of Section 8.3.1 on page 106. The key to exploit SFINAE is to find a type construct that is invalid for function types but not for other types, or vice versa. For class types we can rely on the observation that the pointer-to-member type construct int C::* is valid only if C is a class type. The following program uses this type function to test whether certain types and objects are class types: // traits/isclasst.cpp
#include <iostream> #include "isclasst.hpp"
class MyClass { };
struct MyStruct { };
union MyUnion { };
void myfunc() { }
enumE{e1}e;
// check by passing type as template argument template <typename T> void check() { if (IsClassT<T>::Yes) { std::cout << " IsClassT " << std::endl; } else { std::cout << " !IsClassT " << std::endl; } }
// check by passing type as function call argument template <typename T> void checkT (T) { check<T>(); }
int main() { std::cout << "int: "; check<int>();
std::cout << "MyClass: "; check<MyClass>();
std::cout << "MyStruct:"; MyStruct s; checkT(s);
std::cout << "MyUnion: "; check<MyUnion>();
std::cout << "enum: "; checkT(e);
std::cout << "myfunc():"; checkT(myfunc); }
The program has the following output: int: !IsClassT MyClass: IsClassT MyStruct: IsClassT MyUnion: IsClassT enum: !IsClassT myfunc(): !IsClassT
|
|
|
Записан
|
Странно всё это....
|
|
|
Вад
|
|
« Ответ #132 : 28-09-2009 11:08 » |
|
А, я думал, требуется вообще раздельная компиляция. Так-то ничто не мешает просто использовать SameType при ветвлении.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #133 : 28-09-2009 11:37 » |
|
Вад, ага, вроде то что то похожее на правду, вот в таком виде подошло: template <int v> struct TypesIsSAME { enum {value = v }; };
template <class T, class U> struct IsTypesSame { enum { result = false }; };
template <class T> struct IsTypesSame<T, T> { enum {result = true }; };
template<class T> class X { void Foo(TypesIsSAME<true>) { m_par=m_par.Left(10); }
void Foo(TypesIsSAME<false>) { m_par*=1; } public: void Foo() { TypesIsSAME< IsTypesSame<T, CString>::result > isSame_CString; Foo(isSame_CString); }
T m_par; };
а как не только один тип отличить, а вообще что то вроде свича по типам сделать ? )) (Это не нужно сейчас, но интересно) LogRus, ещё не вник, щас разбираюсь в написанное )
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #134 : 28-09-2009 11:41 » |
|
Вад, кажись понял, можно ведь сделать
TypesIsSAME< IsTypesSame<T, ТИП>::result > isSame_ТИП;
, только придётся каждую нестандартную функцию делать в двух видах - наполненную и пустую
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #135 : 28-09-2009 12:01 » |
|
а как не только один тип отличить, а вообще что то вроде свича по типам сделать ? )) (Это не нужно сейчас, но интересно)
Поскольку программирование в шаблонах чисто функциональное (то есть, там нельзя просто сформировать последовательность действий, в том числе циклы и ветвления), придётся использовать списки типов и построение рекурсивной иерархии типов. Подробно можно почитать про списки типов у того же Александреску, там довольно внятно разбирается Впрочем, если нужно разделять "один тип - одно действие", и ветвление выполняется в runtime, то достаточно модифицировать подход с SameType. template <class Type> struct TypeToType { };
// ... template<class T> void Foo(Type&, TypeToType<T>){}
void Foo(Type& T, TypeToType<CString>) { T=T.Left(10); }
void Foo(Type&, TypeToType<CMyClass>) { }
void Boo(Type& T) { Foo(T, TypeToType<Type>()); } и - да, придётся делать пустую реализацию, если нужен default.
|
|
« Последнее редактирование: 28-09-2009 12:10 от Вад »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #136 : 28-09-2009 13:59 » |
|
и - да, придётся делать пустую реализацию, если нужен default.
причём, для каждого использованного типа )
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #137 : 29-09-2009 06:57 » |
|
Алексей1153++, используй буст Впрочем, если нужно разделять "один тип - одно действие", и ветвление выполняется в runtime, то достаточно модифицировать подход с SameType.
фишка в том что переход выполняется в compile time (точнее выкидывается весь не нужный код), т.к. выражение константно так всё я запутался
|
|
|
Записан
|
Странно всё это....
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #138 : 29-09-2009 07:14 » |
|
LogRus, давай распутаю ))
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #139 : 29-09-2009 07:20 » |
|
LogRus, да, ты прав. Точнее, если Type разный - значит, Boo принадлежит шаблону (или является шаблонной функцией), и будет скомпилировано ровно столько реализаций, сколько нужно, для каждого Type, на самом верхнем уровне вызова
|
|
« Последнее редактирование: 29-09-2009 07:24 от Вад »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #140 : 28-11-2009 17:59 » |
|
имеется такой код class defaultClass { };
template<class T=defaultClass> class A { T m_t; };
можно ли сделать defaultClass безымянным, что-то вроде template<class T=class{}> class A { T m_t; };
?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #141 : 01-01-2010 18:20 » |
|
ещё вопрос: покажите пример переопределения аллокатора. Не могу даже просто унаследовать, запутался в лабиринтах типов: class A { };
template<class T> class CMyAl:public std::allocator<T> { public: template<class _Other> struct rebind { typedef CMyAl<_Other> other; };
/* ... */ };
typedef std::map<int,A,std::less<int>,CMyAl<A> > td_map;
td_map Amap;
ошибка error CMyAl<T>::CMyAl(const CMyAl<T> &) throw(): невозможно преобразовать параметр 1 из 'CMyAl<T>' в 'const CMyAl<T> &' ... ...
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #142 : 02-01-2010 00:41 » |
|
Он же тебе говорит, хочу копирующий конструктор, так сделай его CMyAl(const CMyAl<T> & p) throw() {} CMyAl() throw() {} ЗЫ (Важно!!!) Да, до кучи... надо 2 раза подумать, прежде чем наследоваться от классов stl, дело в том, что они не имеют виртуальных деструкторов!!!
|
|
« Последнее редактирование: 02-01-2010 00:44 от lapulya »
|
Записан
|
С уважением Lapulya
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #143 : 02-01-2010 00:55 » |
|
Алексей1153++, можно ли сделать defaultClass безымянным, что-то вроде зачем?
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #144 : 02-01-2010 04:15 » |
|
lapulya, да мне пофиг на его деструкторы ) Свой сделаю. А насчёт копирующего - где это написано, я вот так и не понял бы сам Или предлагаешь не наследоваться, а вообще полностью весь код аллокатора содрать и переписать ? зачем?
занадом )) Ну я уже понял, что нельзя
|
|
« Последнее редактирование: 02-01-2010 04:20 от Алексей1153++ »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #145 : 02-01-2010 19:16 » |
|
да мне пофиг на его деструкторы ) Свой сделаю. Ну ты даёшь, ну ты рискуешь Ты подумай хорошо, что это означает на самом деле, и насколько аккуратно нужно писать, чтобы не получить утечки памяти.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #146 : 03-01-2010 00:09 » |
|
Алексей1153++, ну для начала, как сказал димка, можно получить утечки. Потом речь идет обо ВСЕХ классах stl (кроме ексепшена вроде), а нетолько об аллокаторе.
Я бы не наследовался (смысла большого нет), если ты пишешь свой аллокатор, то функции выделения и освобождения памяти ты и так перепишешь, а все остальное там только служебное (конструкторы и деструкторы).
ну а понять, что же компилер говорит, можно так, ты посмотри в то место куда он указывает при ошибке, и увидишь, что он указывает на то место где вызывается копирующий конструктор аллокатора, вот компиллер и говорит, что ну нет подходящего (тот что есть не подходит)
|
|
« Последнее редактирование: 03-01-2010 00:16 от lapulya »
|
Записан
|
С уважением Lapulya
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #147 : 03-01-2010 02:52 » |
|
да мне пофиг на его деструкторы ) Свой сделаю. Ну ты даёшь, ну ты рискуешь Ты подумай хорошо, что это означает на самом деле, и насколько аккуратно нужно писать, чтобы не получить утечки памяти. слова, слова... На примере бы показал ) Над чем трясётесть то Ну, то есть, наследоваться не стОит, а просто скопировать интерфейс и переписать ?
|
|
« Последнее редактирование: 03-01-2010 02:54 от Алексей1153++ »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #148 : 03-01-2010 03:48 » |
|
Алексей1153++, и когда ты матчасть выучишь... Ну попробуй запусти нижеследующее. Не знаю, что быстрее случится: core dump или ты Ctrl-C нажать успеешь... class A { private: int *data; public: A(): data(new int[1000000]) { } ~A() { delete[] data; } };
class B: public A { private: int *anotherData; public: B(): A(), anotherData(new int[1000000]) { } ~B() { delete[] anotherData; } };
int main() { for(;;) { A *a = new B(); delete a; } return 0; } В этом вся разница между виртуальным и невиртуальным деструкторами в суперклассе.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #149 : 03-01-2010 04:32 » |
|
Дык я знаю разницу между виртуальным и не виртуальным деструктором, только к данному случаю то это какое отношение А "Ctrl-C" - это о чём ? У мну в студии нет такого сочетания )
|
|
|
Записан
|
|
|
|
|