Comments 17
UFO just landed and posted this here
> можно ли сотворить подобное, не прибегая к помощи лямбд и C++11?
Просто замените лямбды на function objects с виртуальными методами.
Просто замените лямбды на function objects с виртуальными методами.
0
http://www.artima.com/cppsource/type_erasure.html?
Также можно взглянуть на Boost.TypeErasure, который недавно приняли в состав.
Ещё на эту тему есть тут: http://www.youtube.com/watch?v=_BpMYeUFXv8.
Также можно взглянуть на Boost.TypeErasure, который недавно приняли в состав.
Ещё на эту тему есть тут: http://www.youtube.com/watch?v=_BpMYeUFXv8.
+1
Приведённый класс VectorWrapper каким-нибудь существующим cpp-компилером компилируется?
0
Мне вообще шаблоны из-за таких велосипедов и не нравятся. Чем плохи обычные интерфейсы? На интерфейс глянул — и понятно, что нужно передавать. А тут сколько всего нужно прочитать и понять, какие методы должен реализовывать объект-параметр.
0
true-cpp way это сделать функцию fn() шаблонной.
Но поскольку не хочется, не обойтись без вызова функции по указателю (будь это virtual или lambda).
Вот, собственно получилось полностью сохранить семантику VectorWrapper:
Но поскольку не хочется, не обойтись без вызова функции по указателю (будь это virtual или lambda).
Вот, собственно получилось полностью сохранить семантику VectorWrapper:
Скрытый текст
#include <vector>
using namespace std;
template <typename T>
class IVectorWrapper
{
public:
virtual T& operator[](size_t i) = 0;
virtual size_t size() = 0;
virtual ~IVectorWrapper() { }
};
template <typename T, typename C>
class KnownVectorWrapper : public IVectorWrapper<T>
{
public:
KnownVectorWrapper(C& _container) : container(_container) { }
T& operator[](size_t i)
{
return container[i];
}
size_t size()
{
return container.size();
}
private:
C& container;
};
template <typename T>
class VectorWrapper : IVectorWrapper<T>
{
public:
template <typename C>
VectorWrapper(C& _container) : container(new KnownVectorWrapper<T,C>(_container)) { }
~VectorWrapper() { delete container; }
T& operator[](size_t i)
{
return (*container)[i];
}
size_t size()
{
return container->size();
}
private:
IVectorWrapper<T>* container;
};
void fn(VectorWrapper<int> x)
{
int a = 0;
for (size_t i = 0; i < x.size(); ++i)
{
printf("%d ", x[i]);
}
}
void main()
{
vector<int> a;
a.push_back(7);
a.push_back(15);
fn(a);
}
+3
Можно избавиться от new/delete, явно перечислив все возможные контейнеры (их не должно быть много, поэтому не сложно в одном классе это сделать. Также добавляется небольшой оверхед по памяти: sizeof(size_t) на каждый контейнер).
template <typename T>
class VectorWrapper
{
public:
VectorWrapper(vector<T>& _container) : sv(_container), container(&sv) { }
VectorWrapper(QList<T>& _container) : qv(_container), container(&qv) { }
T& operator[](size_t i) { return (*container)[i]; }
size_t size() { return container->size(); }
private:
KnownVectorWrapper<T,vector<T>> sv;
KnownVectorWrapper<T,QList<T>> qv;
IVectorWrapper<T>* container;
};
0
* не указал, что теперь нужен конструктор без параметров
template <typename T, typename C>
class KnownVectorWrapper : public IVectorWrapper<T>
{
public:
KnownVectorWrapper() : container(*(C*)NULL) { }
KnownVectorWrapper(C& _container) : container(_container) { }
// ...
0
> container(*(C*)NULL)
UB.
UB.
0
Да, нужно переписать класс. Если есть сценарии, когда ссылка не инициализирована, лучше использовать указатель.
Практически, инициализация неиспользуемых ссылок dereferenced NULL-ом никогда не вызывала проблем.
Практически, инициализация неиспользуемых ссылок dereferenced NULL-ом никогда не вызывала проблем.
0
угловые скобки пропали в строке
KnownVectorWrapper < T, QList < T > > qv;
KnownVectorWrapper < T, QList < T > > qv;
0
Всякий раз, когда вам нужны функции из C++11 (или даже не вошедшие в него), но нет возможности использовать C++11, смотрите буст. По лямдам, по именованным аргументам, по статическим assert-ам, по хитрым контейнерам и алгоритмам, по потокам, по регулярным выражениям и по концептам в том числе. Тем более ключевое слово «концепт» вы знаете. www.boost.org/doc/libs/1_51_0/libs/concept_check/concept_check.htm. Там же есть описание реализации.
+1
Идея похожа на то что есть в этом докладе (самое начало пример с Point). Там докладчик назвал это SFINAE, только здесь очень сильно упрощенная.
Это конечно круто выглядит (передаем практически любой объект, а функция такая умная что сама определит как с ним правильно работать), но в реальности из-за подобных механизмов очень сильно страдает код, он становится сильно раздутым, непонятным, если описать одним слово — не продакшен (это приминительно к тому что в том докладе, в топике код очень простой).
А второе, я пока не видел ни одного реального примера где бы подобные механизмы реально были бы нужны — это применительно и к топику и докладу (были бы нужны — повышали производительность, читаемость, сопровождаемость кода, вообщем делали бы код лучше). В С++ подобные вещи (указанные в топике) вынесены в алгоритмы, где мы оперируем итераторами и подобный код обычно пишется так:
Это конечно круто выглядит (передаем практически любой объект, а функция такая умная что сама определит как с ним правильно работать), но в реальности из-за подобных механизмов очень сильно страдает код, он становится сильно раздутым, непонятным, если описать одним слово — не продакшен (это приминительно к тому что в том докладе, в топике код очень простой).
А второе, я пока не видел ни одного реального примера где бы подобные механизмы реально были бы нужны — это применительно и к топику и докладу (были бы нужны — повышали производительность, читаемость, сопровождаемость кода, вообщем делали бы код лучше). В С++ подобные вещи (указанные в топике) вынесены в алгоритмы, где мы оперируем итераторами и подобный код обычно пишется так:
template <typename Container>
void fn(Container & c)
{
for (auto & i : c)
{
doSomething(i);
}
}
::std::vector<int> sv;
QList<int> qv;
OtherSuperVector<int> ov;
fn(sv);
fn(qv);
fn(ov);
0
На C++03 можно переделать так:
template <typename T>
class VectorWrapper
{
public:
template <typename C>
VectorWrapper(C& container) :
_getter(boost::bind(&C::operator[], &container, _1)),
_sizeGetter(boost::bind(&C::size, &container))
{
}
T& operator[](size_t i)
{
return _getter(i);
}
size_t size()
{
return _sizeGetter();
}
private:
boost::function<T&(size_t) > _getter;
boost::function<size_t() > _sizeGetter;
};
+4
Всем спасибо за примеры, узнал немного нового…
0
Sign up to leave a comment.
«Концепты» на C++