шаблон , как параметр еще одного шаблона
у вектора еще есть параметры по умолчанию
vector — это не template <class> class
vector — это не template <class> class
И воторой вопрос: у меня есть список. Можно в нем как-нибудь реализовать бинарный поиск? Если бы был итератор с произвольным доступом - то легко, но итератор-то двунаправленный (вроде)
Как тут быть — ХЗ.
Как тут быть — ХЗ.
нет, нельзя
Я и vector<int> пробовал - все равно ругается.
Посмотри определение типа vector
vector<int> - это тем более не template<class> class
Знаю, там их много. Но другие же даны по умолчанию (аллокатор и пр. так?
В общем посмотри определения стандартных адаптеров типа stack и queue и посмотри как они там это обошли.
Да, это неудобно, тоже когда-то с этим сталкивался.
Да, это неудобно, тоже когда-то с этим сталкивался.
точно, спасибо.
а, не обошли они.
просто-напросто использовали не классы-шаблоны в качестве параметров, а обыкновенные классы.
просто-напросто использовали не классы-шаблоны в качестве параметров, а обыкновенные классы.
Да, я стандартной библиотекой давно не пользовался, у нас на работе своя.
Там действительно дублируется. Надо думать.
Там действительно дублируется. Надо думать.
Ну все же раз в std так сделано, может и тебе так же поступить? Откажись от шаблонных шаблонных параметров и используй просто класс-контейнер. И инстанцируй vector<int>'ом.
Вот такие мысли.
Вот такие мысли.
Так подойдет?
template<template<class> class Cont, class U> typename
Cont<U>::iterator f(Cont<U>& d, const U& u){
return d.begin;
}
template < class T >
class TVector : public vector < T > {
};
void Test {
TVector < int > v1;
int x = 5;
vector < int >::iterator it = f(v1, x);
}
Нет. По нескольким причинам.
Каким?
Каким?все использования класса vector придется заменить на использование своего класса TVector
а это скорее всего будет невозможно даже при мало-мальском использовании чужого (или ранее написанного) кода
Я просто вопрос понял "как вызвать эту функцию, если у меня есть вектор". А не "как написать модную фунцию, которая работает от вектора". То есть если уже есть такая функция ровно с тем объявлением, что задано в первом посте и нужно вызвать ее от вектора (а не так, как используется в остальном коде) - то, как мне кажется, мой метод подойдет.
Если вопрос в том, как правильно написать функцию f - то да, мое решение явно не для этого.
Если вопрос в том, как правильно написать функцию f - то да, мое решение явно не для этого.
Если вопрос про то, какой должен быть интерфейс у функции f, чтобы работало с STL контейнерами, то нужно, видимо, писать так:
template<template<class, class> class Cont, class U, class A> typename
Cont<U, A >::iterator f(Cont<U, A >& d, const U& u)
{
return d.begin;
}
void Test {
vector < int > v1;
int x = 5;
vector < int >::iterator it = f(v1, x);
}
Каким?Первую привел , а именно: нельзя использовать с vector напрямую, хотя замысел автора, очевидно, и состоял в том, чтобы использовать с любым контейнером. Таким образом приведенный код — это НЕ решение задачи.
Вторая причина более спорная на первый взгляд — добавление пустого производного класса, чтобы сделать workaround. Очень неоднозначное решение. Вообще наследование так использовать не стоит.
Я просто вопрос понял "как вызвать эту функцию, если у меня есть вектор". А не "как написать модную фунцию, которая работает от вектора".Ну и как ее использовать-то, если есть вектор? Если мы не меняем функцию, тогда надо юзать reinterpret_cast (ну или обмануть себя и написать-таки static_cast). В общем к сожалению это не решение. Хотя можно добавить в TVector конструктор от vector< int >, но это чревато проблемами. Лучше тогда уж написать в стиле адаптера: указатель на vector< int > как данное-член.
Это уже лучше, так перегрузить исходный шаблон из первого поста можно, это будет работать, если типы вектора и второго параметра совпадают.
Минусы:
непереносимо, строго говоря: мы полагаемся на конкретную реализацию шаблона vector (стандарт говорит лишь о том, что можно инстанцировать vector< T > при определенных условиях на тип T, но ничего не говорит о том, как это сделано: есть ли там еще дополнительные параметры и об их количестве).
второй, опять же, более сомнительный (многим и первый покажется очень сомнительным но это неоправданное усложнение функции, подстраивание ее под определенное описание контейнера: шаблонный класс с двумя параметрами-типами, причем второй тип передается без изменений.
Все же предлагаю свое решение, как наиболее общее и лишенное перечисленных недостатков: модифицировать определение f следующим образом:
Плюс/Минус: позволяет вызвать f, причем вторым параметром передать не строго тип, на который настроен шаблон, а все, что синтаксически корректно при использовании соответствующей функции.
Плюс в том, что по идеологии везде, где принимается ссылка/указатель на базовый класс, позволить принимать ссылку/указатель на производный. В этом случае
Что выбирать — решать автору.
Как дополнительный аргумент в пользу этого подхода приведу (повторно) следующий: в std шаблонные классы-адаптеры сделаны именно так.
Минусы:
непереносимо, строго говоря: мы полагаемся на конкретную реализацию шаблона vector (стандарт говорит лишь о том, что можно инстанцировать vector< T > при определенных условиях на тип T, но ничего не говорит о том, как это сделано: есть ли там еще дополнительные параметры и об их количестве).
второй, опять же, более сомнительный (многим и первый покажется очень сомнительным но это неоправданное усложнение функции, подстраивание ее под определенное описание контейнера: шаблонный класс с двумя параметрами-типами, причем второй тип передается без изменений.
Все же предлагаю свое решение, как наиболее общее и лишенное перечисленных недостатков: модифицировать определение f следующим образом:
template<class Cont, class U> typename
Cont::iterator f(Cont& d, const U& u)
{
return d.begin;
}
void Test {
vector < int > v1;
int x = 5;
vector < int >::iterator it = f(v1, x);
}
Плюс/Минус: позволяет вызвать f, причем вторым параметром передать не строго тип, на который настроен шаблон, а все, что синтаксически корректно при использовании соответствующей функции.
Плюс в том, что по идеологии везде, где принимается ссылка/указатель на базовый класс, позволить принимать ссылку/указатель на производный. В этом случае
struct A {};
struct B : A {};
void Test {
vector < A* > v1;
B* x = new B;
vector < A* >::iterator it = f(v1, &x);
}
сработает с моим определением, но не сработает с твоим.Что выбирать — решать автору.
Как дополнительный аргумент в пользу этого подхода приведу (повторно) следующий: в std шаблонные классы-адаптеры сделаны именно так.
Глобально: зачем нужен шаблонный параметр шаблона?
Отнюдь не для того, чтобы потренировать компилятор в выведении типов. В подавляющем большинстве случаев шаблонный шаблонный параметр надо указывать явно: для реализации шаблонных классов с поддержкой стратегий, например. В том случае, когда этот параметр выводится компилятором, плюсы исчезают. Если у кого-нибудь есть соображения, будет интересно выслушать.
Отнюдь не для того, чтобы потренировать компилятор в выведении типов. В подавляющем большинстве случаев шаблонный шаблонный параметр надо указывать явно: для реализации шаблонных классов с поддержкой стратегий, например. В том случае, когда этот параметр выводится компилятором, плюсы исчезают. Если у кого-нибудь есть соображения, будет интересно выслушать.
Вообще я сейчас обедал и почти тоже самое пришло в голову. Тоже перестал понимать зачем использовать такую сложную конструкцию. Как понимаю, можно обойтись просто вот этим:
template<class Cont> typename
Cont::iterator f(Cont& d, const typename Cont::value_type& u){
return d.begin;
}
void Test {
vector < int > v1;
int x = 5;
vector < int >::iterator it = f(v1, x);
}
Ну и как ее использовать-то, если есть вектор? Если мы не меняем функцию, тогда надо юзать reinterpret_cast (ну или обмануть себя и написать-таки static_cast).Я это и имел ввиду, просто не тот кусок скопировал (только сейчас заметил). В момент вызова функции вместо vector подставить другой тип, у которого будет тот же самый адрес this. Это, конечно, жутко неправильно, но как временное решение может подойти.
Приятного аппетита.
Да, это круто. Если это написать вместо моего кода, то слова «Плюс/минус» можно вполне заменить на «плюс».
Сомнительна лишь необходимость определения типа/typedef'а value_type внутри всех контейнеров, используемых с этой функцией.
Да, это круто. Если это написать вместо моего кода, то слова «Плюс/минус» можно вполне заменить на «плюс».
Сомнительна лишь необходимость определения типа/typedef'а value_type внутри всех контейнеров, используемых с этой функцией.
Вообще предлагаю тут подумать и понять, почему C++ не позволяет использовать шаблоны с параметрами по умолчанию в качестве аргументов-шаблонных параметров с отличным от полного количеством параметров. Надеюсь, ясно, что имел в виду: то, что в первом посте: почему нельзя подставить vector в то, что написал топикстартер.
Ответ подразумевается в виде: если бы это позволили, то вышел бы такой-то такой-то пиздец.
Ответ подразумевается в виде: если бы это позволили, то вышел бы такой-то такой-то пиздец.
[offtop] Да я в смысле уже пообедал, как раз это время не был на форуме и ответил позднее [/offtop]
Вообще, как я понимаю, value_type так или иначе определяют во всех контейнерах. Если работают со своими - то он там может называться по другому, но тогда, как я понимаю, с помощью полиси компании запрещают пользоваться контейнерами из STL. Так что, скорее всего, этот typedef есть.
Твое решение мне тоже нравится. Просто мой вариант чуть отличается и решил его тоже запостить.
Вообще, как я понимаю, value_type так или иначе определяют во всех контейнерах. Если работают со своими - то он там может называться по другому, но тогда, как я понимаю, с помощью полиси компании запрещают пользоваться контейнерами из STL. Так что, скорее всего, этот typedef есть.
Твое решение мне тоже нравится. Просто мой вариант чуть отличается и решил его тоже запостить.
Да, это верно. В нашей компании, например, есть контейнеры с различным числом шаблонных параметров, в этом случае необходимо одно из последних двух решений здесь, все что выше — хуже.
По поводу value_type у меня просто был загон в сторону нешаблонных контейнеров.
По поводу value_type у меня просто был загон в сторону нешаблонных контейнеров.
По поводу value_type у меня просто был загон в сторону нешаблонных контейнеров.Дык вроде там тоже можно определить этот typedef. Ничего плохого в тех контейнерах от наличия такого typedef не случится, зато добавит гибкости когда их используют шаблонные функции.
PS
На твой основной вопрос (почему плохо работают параметры по умолчанию в шаблонах) я потом (дома) отвечу. Это ближе к утру по московскому времени будет.
Вообще предлагаю тут подумать и понять, почему C++ не позволяет использовать шаблоны с параметрами по умолчанию в качестве аргументов-шаблонных параметров с отличным от полного количеством параметров. Надеюсь, ясно, что имел в виду: то, что в первом посте: почему нельзя подставить vector в то, что написал топикстартер.На самом деле совсем пиздец не будет, насколько я понимаю. Просто компиляторам придется повозиться и не всегда они смогут в итоге решить, что правильно. Причем, если верить Дэвиду Вандевурду, некоторые компиляторы (как расширение) позволяют это сделать, хоть это и не стандарт.
Ответ подразумевается в виде: если бы это позволили, то вышел бы такой-то такой-то пиздец.
Вообще эта проблема очень близка к проблеме, почему нельзя делать typedef шаблоны. Если бы их можно было делать, то проблема уже обходится легко, например в данном случае можно сделать так:
template < typename T >
typedef vector < T > TVector;
...
f<TVector, int>(v1, x);
Последнее удобно было бы не только в этих примерах. Как понимаю typedef-шаблоны обсуждали в комитете по стандартизации, но вот с ними уже есть подводные камни. Например, вот этот:
void F(long);
template < typename T > typedef T DT;
template < typename T > void F(DT<T>);
int main {
F(42);
}
Я туплю чего-то. А какая там проблема с этим кодом?
Какую из двух функций F вызвать. Для первой нужно преобразовать int в long, а вторая подходит "идеально", если не считать, что там шаблон. Какую бы выбрал ты?
Оставить комментарий
zrab
что-то туплюесть шаблон функции
как его применять? написал
, компилятор ругается.
Помогите, под конец дня голова пухнет