Re: Как упростить инициализацию вектора?
От: collider  
Дата: 03.07.11 20:49
Оценка: 5 (2)
Здравствуйте, Basil2, Вы писали:

B>Вопросы:


B>1. Какие существуют аналогичные решения? (в рамках известных библиотек, типа Boost/Loki)

B>2. Как можно упросить код, связанный с определением конструкторов? (чтобы не писать конструктор под каждый размер)
B>3. Идеи по улучшению и развитию класса? (если делать его универсальным, для использования не только мною)



Предлагаю свою щестеренку в ваш велосипед.
Enum& operator<<(const T& t)
{
push_back(t);
return *this;
}


и тогда

vector<int> valuesToCheck = Enum<int>()<<1<<4<<9<<15;
Re: Как упростить инициализацию вектора?
От: uzhas Ниоткуда  
Дата: 03.07.11 21:07
Оценка: 1 (1) +1
Здравствуйте, Basil2, Вы писали:

B>Для решения проблемы я написал небольшой класс, по которому ищу обратную связь.

коротко: класс не нужен
решения:
классика
http://ideone.com/pwstw
драфт
http://ideone.com/SnwU7
Re[5]: Как упростить инициализацию вектора?
От: _nn_ www.nemerleweb.com
Дата: 05.07.11 12:05
Оценка: 4 (1)
Здравствуйте, Basil2, Вы писали:

B>Здравствуйте, _nn_, Вы писали:


__>>Boost.Exception ?

B>Boost.Exception несколько про другое. Добавление predefined типов мне излишне, равно как необходимоть их определения.

B>Потом, подобный класс может использоваться не только в исключениях, например:

B>
B>LogError(Msg() << "Shit happend: " << errorCode);
B>


std::stringstream для этого и предназначен:

#include <sstream>
#include <iostream>
#include <string>

using namespace std;

struct Wrapper
{
  Wrapper() {}

  template<typename T>
  Wrapper const& operator<<(T const& t) const { s << t; return *this; }

  operator string() const { return s.str(); }

  mutable ostringstream s;
};

string f()
{
  return Wrapper() << "A" << "B" << "C";
}

int main()
{
  cout << f();
}


http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Как упростить инициализацию вектора?
От: jazzer Россия Skype: enerjazzer
Дата: 03.07.11 23:49
Оценка: +1
Здравствуйте, Basil2, Вы писали:

B>этого не позволяет даже Boost Assign.

В смысле — не позволяет?
Передавай assign::list_of в эту функцию вместо вектора, всего делов.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Как упростить инициализацию вектора?
От: DezzzFabius  
Дата: 04.07.11 07:44
Оценка: :)
Здравствуйте, collider, Вы писали:

...

C>Предлагаю свою щестеренку в ваш велосипед.

C>Enum& operator<<(const T& t)
C> {
C> push_back(t);
C> return *this;
C> }


C>и тогда


C>vector<int> valuesToCheck = Enum<int>()<<1<<4<<9<<15;


Ваша шестерёнка заменила весь двигатель
И ещё, я бы использовал наследование.

template <typename T>
class vector_init: public vector<T>
{
public:
vector_init(int n = 0) { if (n > 0) reserve(n);} // необязательный момент оптимизации
vector_init& operator <<( const T& _Val ) { this->push_back(_Val); return *this;} // в этом методе хорошо бы добавлять только не уникальный _Val
};


...

CheckCategoriesExtraction(AvatarMovie, vector_init<Category>()<<categFantastic);
CheckCategoriesExtraction(TitanicMovie, vector_init<Category>(2)<<categHistoric<<categDrama);
Re: Как упростить инициализацию вектора?
От: IROV..  
Дата: 04.07.11 16:54
Оценка: :)
Здравствуйте, Basil2, Вы писали:

B>Преимущества:

B>1. Просто и удобно.
B>2. Легко встраивать в имеющийся код (за счет создания Enum'а по одному значению и автоматического присвоения обычному вектору).
Вот жаль проблема надуманая, неужели мы будем категории писать в C++?
Даже если это Unit test тогда можно не заморачиваться и написать пару раз push_back вместо того, что бы..... писать еще один юнит тест на эту поделку

З.Ы. если уж так сильно хочеться

предлагаю переопределить оператор +.
И завести два класса, Контейнер Категорий и просто категории.
я не волшебник, я только учусь!
Как упростить инициализацию вектора?
От: Basil2 Россия https://starostin.msk.ru
Дата: 03.07.11 15:37
Оценка:
Для затравки — пример.
Пускай у нас есть функция, которая на входе принимает фильм, а на выходе выдает к каким жанрам он относится:
GetFilmCategories(const Film& film, vector<Category>& categories);

И мы пишем к ней юнит-тесты. Тогда в тестах логичен такой код:
// Функция-хелпер: извлечь категории и проверить их соответствие переданному списку
CheckCategoriesExtraction(const Film& film, const vector<Category>& categories);

CheckCategoriesExtraction(AvatarMovie, список_категорий_Аватара); 
CheckCategoriesExtraction(TitanicMovie, список_категорий_Титаника);

Беда в том, что C++ не позволяет передать в функцию набор значений вектора. Более того, этого не позволяет даже Boost Assign. А С++0x, где это обещается, пока не вышел...

Для решения проблемы я написал небольшой класс, по которому ищу обратную связь.
Класс такой:
template<typename T>
class Enum
{
    typedef vector<T> Container;
    Container m_data;

public:
    Enum() {}; // makes empty vector

    // Non-explicit - can create Enum by single value
    Enum(T t1)
    {
       m_data.push_back(t1);
    }

    // Several elements ctors
    Enum(T t1, T t2)
    {
       m_data.push_back(t1);
       m_data.push_back(t2);
    }
    Enum(T t1, T t2, T t3)
    {
       m_data.push_back(t1);
       m_data.push_back(t2);
       m_data.push_back(t3);
    }

    // several other constructors... //

    size_t size() const
    {
        return m_data.size();
    }
    void push_back(const T& t)
    {
        m_data.push_back(t);
    }
    T& operator[](size_t i)
    {
        if (i >= m_data.size())
            throw std::out_of_range("Enum<> operator[] bad index!");
        return m_data[i];
    }

    // For easy assigning
    operator Container()
    {
        return m_data;
    }
};

Соответственно, класс позволяет использовать такие конструкции:
typedef Enum<Category> Categories;

CheckCategoriesExtraction(AvatarMovie, categFantastic); // one category only - no need of Enum
CheckCategoriesExtraction(TitanicMovie, Categories(categHistoric, categDrama));
CheckCategoriesExtraction(EmptyMovie, Categories()); // film w/o categories

vector<Category> categoriesIlike = Categories(categAction, categComedy);
vector<int> valuesToCheck = Enum<int>(1, 4, 9, 15);

Преимущества:
1. Просто и удобно.
2. Легко встраивать в имеющийся код (за счет создания Enum'а по одному значению и автоматического присвоения обычному вектору).

Вопросы:

1. Какие существуют аналогичные решения? (в рамках известных библиотек, типа Boost/Loki)
2. Как можно упросить код, связанный с определением конструкторов? (чтобы не писать конструктор под каждый размер)
3. Идеи по улучшению и развитию класса? (если делать его универсальным, для использования не только мною)
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
c++ vector container assignment initialization
Re[3]: Как упростить инициализацию вектора?
От: collider  
Дата: 04.07.11 09:31
Оценка:
Здравствуйте, DezzzFabius, Вы писали:


DF>И ещё, я бы использовал наследование.


DF>template <typename T>

DF>class vector_init: public vector<T>
DF>{
DF>public:
DF> vector_init(int n = 0) { if (n > 0) reserve(n);} // необязательный момент оптимизации
DF> vector_init& operator <<( const T& _Val ) { this->push_back(_Val); return *this;} // в этом методе хорошо бы добавлять только не уникальный _Val
DF>};


DF>...


DF> CheckCategoriesExtraction(AvatarMovie, vector_init<Category>()<<categFantastic);

DF> CheckCategoriesExtraction(TitanicMovie, vector_init<Category>(2)<<categHistoric<<categDrama);



нет предела совершенству



class _vector_init0;

template <typename T>
class _vector_init1: public std::vector<T>
{
    typedef std::vector<T> parent;
private:
    friend class _vector_init0;
    _vector_init1(size_t n,const T& _Val)
    {
        if(n) reserve(n);
        push_back(_Val);
    } 
public:
    _vector_init1& operator <<( const T& _Val ) { push_back(_Val); return *this;} 

};


class _vector_init0
{
public:
    _vector_init0(size_t n=0):_count(n) {} 

    template <typename T>
    _vector_init1<T> operator<<( const T& _Val ) { return _vector_init1<T>(_count,_Val);} 
private:
    size_t _count;
};

typedef _vector_init0  vector_init;


//.............

CheckCategoriesExtraction(AvatarMovie, vector_init()<<categFantastic);
CheckCategoriesExtraction(TitanicMovie, vector_init(2)<<categHistoric<<categDrama);
Re[2]: Как упростить инициализацию вектора?
От: Basil2 Россия https://starostin.msk.ru
Дата: 04.07.11 13:43
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Basil2, Вы писали:


B>>Для решения проблемы я написал небольшой класс, по которому ищу обратную связь.

U>коротко: класс не нужен
U>решения:
U>классика
U>http://ideone.com/pwstw

Прикольный способ
Однако, как я понимаю, там всегда необходимы 2 строчки кода, а не одна?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: Как упростить инициализацию вектора?
От: Basil2 Россия https://starostin.msk.ru
Дата: 04.07.11 14:43
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, Basil2, Вы писали:


B>>этого не позволяет даже Boost Assign.

J>В смысле — не позволяет?
J>Передавай assign::list_of в эту функцию вместо вектора, всего делов.
Ммм..., тоже верно

Наверное, мне синтаксис этого list_of()()() не понравился, когда я на него смотрел
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: Как упростить инициализацию вектора?
От: Basil2 Россия https://starostin.msk.ru
Дата: 04.07.11 15:24
Оценка:
Здравствуйте, collider, Вы писали:

B>>3. Идеи по улучшению и развитию класса? (если делать его универсальным, для использования не только мною)


C>Предлагаю свою щестеренку в ваш велосипед.

C>Enum& operator<<(const T& t)
C> {
C> push_back(t);
C> return *this;
C> }
C>и тогда
C>vector<int> valuesToCheck = Enum<int>()<<1<<4<<9<<15;

Кстати, это навевает идею для решения другой проблемы юнит-тестов (и не только).

Пусть есть такой код:
const char *url;
if (shitHappend)
{
   string errMsg = string("Shit happpend: on url ") + url;
   throw exception(errMsg.c_str());
}

Или:
int errorCode;
if (shitHappend)
{
   stringstream str;
   str << "Shit happpend: on url " << url << " errcode=" << errorCode;
   throw exception(str.str().c_str());
}


Многовато кода для обработки одной ошибки, IMHO.
Хочется видеть более короткое решение, типа:
if (shitHappend)
   throw exception("Shit happpend: on url " + url + " errcode=" + errorCode);

Или хотя бы:
if (shitHappend)
   throw exception(Msg()<<"Shit happpend: on url "<<url<<" errcode="<<errorCode);
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[3]: Как упростить инициализацию вектора?
От: _nn_ www.nemerleweb.com
Дата: 04.07.11 16:05
Оценка:
Здравствуйте, Basil2, Вы писали:

B>Многовато кода для обработки одной ошибки, IMHO.

B>Хочется видеть более короткое решение, типа:
B>
B>if (shitHappend)
B>   throw exception("Shit happpend: on url " + url + " errcode=" + errorCode);
B>

B>Или хотя бы:
B>
B>if (shitHappend)
B>   throw exception(Msg()<<"Shit happpend: on url "<<url<<" errcode="<<errorCode);
B>


Boost.Exception ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Как упростить инициализацию вектора?
От: Basil2 Россия https://starostin.msk.ru
Дата: 05.07.11 11:05
Оценка:
Здравствуйте, IROV.., Вы писали:

IRO>Вот жаль проблема надуманая, неужели мы будем категории писать в C++?

IRO>Даже если это Unit test тогда можно не заморачиваться и написать пару раз push_back вместо того, что бы..... писать еще один юнит тест на эту поделку

Пару?? Даже в приведенном примере требуется минимум 5 push_back, а таких тестов в коде десятки!

IRO>предлагаю переопределить оператор +.

IRO>И завести два класса, Контейнер Категорий и просто категории.
Идея интересная, оператор+ складывает два класса и возвращает вектор
А как быть, если категория одна или их нет?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[4]: Как упростить инициализацию вектора?
От: Basil2 Россия https://starostin.msk.ru
Дата: 05.07.11 11:10
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Boost.Exception ?

Boost.Exception несколько про другое. Добавление predefined типов мне излишне, равно как необходимоть их определения.

Потом, подобный класс может использоваться не только в исключениях, например:
LogError(Msg() << "Shit happend: " << errorCode);
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[3]: Как упростить инициализацию вектора?
От: IROV..  
Дата: 05.07.11 11:28
Оценка:
Здравствуйте, Basil2, Вы писали:

B>Пару?? Даже в приведенном примере требуется минимум 5 push_back, а таких тестов в коде десятки!

А как ты их используешь в "рабочем" коде?

IRO>>предлагаю переопределить оператор +.

IRO>>И завести два класса, Контейнер Категорий и просто категории.
B>Идея интересная, оператор+ складывает два класса и возвращает вектор
B>А как быть, если категория одна или их нет?
У контейнера конструктор на одну категорию, и также пустой конструктор.
Лучше, отсутсвие категории — делать перегрузкой функции/создать спец функцию w\o

я не волшебник, я только учусь!
Re[6]: Как упростить инициализацию вектора?
От: Basil2 Россия https://starostin.msk.ru
Дата: 07.07.11 13:17
Оценка:
Здравствуйте, _nn_, Вы писали:

__>std::stringstream для этого и предназначен:


Через него и предполагалось делать, спасибо за готовый пример!!
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.