шаблон , как параметр еще одного шаблона
vector — это не template <class> class
Как тут быть — ХЗ.
нет, нельзя
Я и vector<int> пробовал - все равно ругается.
Посмотри определение типа vector
vector<int> - это тем более не template<class> class
Знаю, там их много. Но другие же даны по умолчанию (аллокатор и пр. так?
Да, это неудобно, тоже когда-то с этим сталкивался.
точно, спасибо.
просто-напросто использовали не классы-шаблоны в качестве параметров, а обыкновенные классы.
Там действительно дублируется. Надо думать.
Вот такие мысли.
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 - то да, мое решение явно не для этого.
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 следующим образом:
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 внутри всех контейнеров, используемых с этой функцией.
Ответ подразумевается в виде: если бы это позволили, то вышел бы такой-то такой-то пиздец.
Вообще, как я понимаю, value_type так или иначе определяют во всех контейнерах. Если работают со своими - то он там может называться по другому, но тогда, как я понимаю, с помощью полиси компании запрещают пользоваться контейнерами из STL. Так что, скорее всего, этот typedef есть.
Твое решение мне тоже нравится. Просто мой вариант чуть отличается и решил его тоже запостить.
По поводу 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
что-то туплюесть шаблон функции
как его применять? написал
, компилятор ругается.
Помогите, под конец дня голова пухнет