Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> возвратить из функции void? 
V
    Опции темы
tilin
Дата 27.10.2009, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Класс А наследуется от IBase в котором есть метод Get(). В классе А этот метод переопределяется для возвращения конкретных значений. Нижеследующий пример конечно не работает, потому что возвращаемые типы Get() отличаются. А как вообще такое можно сделать. 

Код

class IBase
{
  virtual void Get() = 0;
};

template <class T>
class A : public IBase
{
  T value;
  T Get()
  {
    return value;
  }
};



PM MAIL   Вверх
Alek86
Дата 27.10.2009, 14:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



tilin, что значит "не работает"?
что ты от него ожидаешь?
допиши, в коде, желательно


--------------------
user posted image    user posted image
PM MAIL   Вверх
azesmcar
Дата 27.10.2009, 14:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата(tilin @  27.10.2009,  14:10 Найти цитируемый пост)
А как вообще такое можно сделать. 

Такое - никак. А что конкретно надо сделать? Можно к примеру возвращать boost::any, boost::variant. Побольше расскажи о задаче.

PM   Вверх
tilin
Дата 27.10.2009, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Не работает, значит не компилируется и ругается на то, что разные типы возвращаемых значений у IBase::Get и A::Get.

Чего хочется:

Код


class C
{

};

vector<IBase*> v;

v.push_back(new A<int>);
v.push_back(new A<float>);
v.push_back(new A<C>);

int i = v[0]->Get();
float f = v[1]->Get();
C c = v[2]->Get();

PM MAIL   Вверх
Andrey44
Дата 27.10.2009, 14:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1501
Регистрация: 4.12.2006
Где: На работе

Репутация: 2
Всего: 26



Цитата(tilin @  27.10.2009,  14:10 Найти цитируемый пост)
virtual void Get() = 0


Цитата(tilin @  27.10.2009,  14:10 Найти цитируемый пост)
T Get()  {    return value;  }

А где же они будут одинаковыми? void!=T


--------------------
????? ??, ??????? ?????.  smile 
PM MAIL WWW ICQ   Вверх
tilin
Дата 27.10.2009, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(Andrey44 @  27.10.2009,  14:34 Найти цитируемый пост)
А где же они будут одинаковыми? void!=T 


Оно и понятно ) Это я для примера просто.
PM MAIL   Вверх
Alek86
Дата 27.10.2009, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



tilin, такое, как ты показал, невозможно
или boost::any или dynamic_cast


--------------------
user posted image    user posted image
PM MAIL   Вверх
niXman
Дата 27.10.2009, 15:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 211
Регистрация: 4.7.2009

Репутация: 0
Всего: 0



Цитата(Alek86 @  27.10.2009,  12:52 Найти цитируемый пост)
boost::any

Наверное это будет сложно для начинающего.
Напиши микро-аналог variant. Что-то типа этого:
Код

class Variant {
public:
    Variant():_data() {}
    Variant(const std::string& v):_data(v) {}
    Variant(const Variant& v):_data(v._data) {}
    ~Variant() {}
    /*  */
    bool is_empty() const { return _data.empty(); }
    /*  */
    std::string to_string() const { return _data; }
    int to_int() const {
        if ( is_empty() ) return -1;
        return atoi(_data.c_str());
    }
    long long to_int64() const {
        if ( is_empty() ) return -1;
        return (long long)atof(_data.c_str());
    }
    double to_double() const {
        if ( is_empty() ) return -1;
        return atof(_data.c_str());
    }
private:
    std::string _data;
};


Это сообщение отредактировал(а) niXman - 27.10.2009, 15:03
--------------------
if ( !c++ ) {   *power--;   this->wussiness += 10;}
PM MAIL   Вверх
bsa
Дата 27.10.2009, 15:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



tilin, интересно, а как ты этим пользоваться собирался? Вот например, кусок кода не знает ничего о типе Type, для которого был в другом месте кода создан экземляр класса A<Type>... Так вот, что будет делать твой кусок кода с тем, что вернет A<Type>::Get? Я уж не говорю о том, что это даже теоретически скомпилировать нельзя.
PM   Вверх
tilin
Дата 27.10.2009, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(bsa @ 27.10.2009,  15:10)
tilin, интересно, а как ты этим пользоваться собирался? Вот например, кусок кода не знает ничего о типе Type, для которого был в другом месте кода создан экземляр класса A<Type>... Так вот, что будет делать твой кусок кода с тем, что вернет A<Type>::Get? Я уж не говорю о том, что это даже теоретически скомпилировать нельзя.

Ну кратко так:

A<type> создается в одном месте кода, затем помещается в массив. С массивом работает код, который может например определенным образом сортировать элементы массива, добавлять, удалять и т.д. А где-то из этого массива извлекается значение A<type> и используется. Смысл в том, что тот кто помещает в массив и тот кто извлекает из массива имеют нужную информацию о типах. А массив может содержать конечно только элементы одного типа, отсюда и наследование от единого интерфейса.
PM MAIL   Вверх
Alek86
Дата 27.10.2009, 15:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(tilin @  27.10.2009,  15:22 Найти цитируемый пост)
Смысл в том, что тот кто помещает в массив и тот кто извлекает из массива имеют нужную информацию о типах. А массив может содержать конечно только элементы одного типа, отсюда и наследование от единого интерфейса.

тогда dynamic_cast
а если ну совсем уверен, то даже static_cast вниз по иерархии

Это сообщение отредактировал(а) Alek86 - 27.10.2009, 15:40


--------------------
user posted image    user posted image
PM MAIL   Вверх
tilin
Дата 27.10.2009, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(Alek86 @ 27.10.2009,  15:38)
тогда dynamic_cast
а если ну совсем уверен, то даже static_cast вниз по иерархии

При получении значения static_cast до требуемого типа вполне подходит. И как я понял других вариантов, кроме как возвращать Variant, нет. Буду делать так. Спасибо. 

Меня только смущает, что в этом случае требуется создавать временный объект Variant в функции Get(). 

Это сообщение отредактировал(а) tilin - 27.10.2009, 16:17
PM MAIL   Вверх
niXman
Дата 27.10.2009, 20:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 211
Регистрация: 4.7.2009

Репутация: 0
Всего: 0



Цитата(tilin @  27.10.2009,  13:53 Найти цитируемый пост)
Меня только смущает, что в этом случае требуется создавать временный объект Variant в функции Get().

Создай локальный в твоем классе, инициализируй его в функции Get(), и возвращай на него ссылку.
--------------------
if ( !c++ ) {   *power--;   this->wussiness += 10;}
PM MAIL   Вверх
Lazin
Дата 27.10.2009, 20:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



можно использовать паттерн - visitor

Код

class IVisitor
{
public:
  virtual void operator()(int) = 0;
  virtual  void operator()(double) = 0; 
  virtual  void operator()(std::vector<char> const&) = 0;
  ...
};

class IBase
{
  virtual void Apply(IVisitor&) = 0;
};

template <class T>
class A : public IBase
{
  T value;
  void Apply(IVisitor& visitor)
  {
     visitor(value);
  }
};

class MyVisitor
{
public:
  virtual void operator()(int p)
  {
     std::cout << p << std::endl;
  }
  virtual  void operator()(double)
  {
     std::cout << p << std::endl;
  }
  virtual  void operator()(std::vector<char> const& p)
  {
      std::copy(p.begin(), p.end(), std::ostream_iterator(std::cout, ' '));
      std::cout << std::endl;
  }
};
....
vector<IBase*> v;
v.push_back(new A<int>);
v.push_back(new A<float>);
v.push_back(new A<C>);

MyVisitor myVisitor;

for(int i = 0; i < v.size(); ++i)
    v[i]->Apply(myVisitor);

PM MAIL Skype GTalk   Вверх
tilin
Дата 27.10.2009, 22:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(niXman @ 27.10.2009,  20:37)
Создай локальный в твоем классе, инициализируй его в функции Get(), и возвращай на него ссылку.

Так и сделал. Только не в Get, а сразу при создании объекта. А Get возвращает Вариант.
PM MAIL   Вверх
tilin
Дата 27.10.2009, 23:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(Lazin @ 27.10.2009,  20:54)
можно использовать паттерн - visitor

А в этом случае не придется для каждого типа добавлять новый оператор в IVisitor? Если да, то не подходит.

Это сообщение отредактировал(а) tilin - 27.10.2009, 23:25
PM MAIL   Вверх
Lazin
Дата 28.10.2009, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(tilin @  27.10.2009,  23:25 Найти цитируемый пост)
А в этом случае не придется для каждого типа добавлять новый оператор в IVisitor? Если да, то не подходит.

если они однотипные, то их можно сгенирировать с помощью шаблона

если ты будешь использовать variant, то у тебя в коде будет что-то вроде - 

Код

Variant v = p->Get();
if(v.isInteger())
 ...
else if(v.isString())
 ... //итд

visitor - это то-же самое, только принятие решения, о том, как обрабатывать значение ложится на компилятор (перегрузка ф-ии) и в любом случае, тебе придется написать код для разных типов(либо использовать шаблон, для нескольких похожих типов)
PM MAIL Skype GTalk   Вверх
tilin
Дата 28.10.2009, 00:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(Lazin @ 28.10.2009,  00:01)
это то-же самое, только принятие решения, о том, как обрабатывать значение ложится на компилятор (перегрузка ф-ии) и в любом случае, тебе придется написать код для разных типов(либо использовать шаблон, для нескольких похожих типов)

Типы могут быть любые. Вариант у меня выглядит вот так:

Код

class Variant
{
private:
    class IType
    {
    public:
        virtual ~IType()
        {
        }
    };
    typedef auto_ptr<IType> pIType;
    template <class T>
    class Type : public IType
    {
    public:
        T object;
        Type(T const& t)
        : object(t)
        {
        }
    };
    pIType itype;
public:
    template <class T>
    Variant& operator = (T const& t)
    {
        typedef Type<T> cType;
        itype = auto_ptr<cType>(new cType(t));
        return *this;
    }

    template <class T>
    operator T ()
    {
        typedef Type<T> cType;
        cType& type = dynamic_cast<cType&>(*itype);
        return type.object;
    }
};



В классе есть 
Код
Variant result;


В коде значение получается например так: 
Код
SomeClass* res = Object->Get();


PM MAIL   Вверх
Lazin
Дата 28.10.2009, 06:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(tilin @  28.10.2009,  00:11 Найти цитируемый пост)
В коде значение получается например так

и как-же ты с ними работаешь потом, если не секрет?
PM MAIL Skype GTalk   Вверх
tilin
Дата 28.10.2009, 08:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(Lazin @ 28.10.2009,  06:20)
и как-же ты с ними работаешь потом, если не секрет?

Вопрос не совсем понял, но например в варианте с int так:

Код

vector<IBase*> v;
v.push_back(new A<int>);
int i = v[0]->Get();

int vvp = i * 200;
cout << vvp << endl;


PM MAIL   Вверх
Lazin
Дата 28.10.2009, 09:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(tilin @  28.10.2009,  08:52 Найти цитируемый пост)
Код

vector<IBase*> v;
v.push_back(new A<int>);
int i = v[0]->Get();
int vvp = i * 200;
cout << vvp << endl;


во первых, здесь нужно явное приведение типа (static_cast), во вторых, если в v[0] не int - оператор приведения типа бросит исключение, мне интересно, что ты будешь делать, если у тебя в одном контейнере значения разных типов, как в твоем первом примере?

Код

vector<IBase*> v;
v.push_back(new A<int>());
v.push_back(new A<double>());
...
v.push_back(new A<Foo>());
...
for(vector<IBase*>::iterator i = v.begin(); i != v.end(); ++i)
{
    undefined_type value = static_cast<undefined_type>((*i)->Get()); //????
}

PM MAIL Skype GTalk   Вверх
tilin
Дата 28.10.2009, 09:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Вот пример - код рабочий.

Код

#include <memory>
#include <vector>
#include <iostream>

using namespace std;


class Variant
{
private:
    class IType
    {
    public:
        virtual ~IType()
        {
        }
    };
    typedef auto_ptr<IType> pIType;
    template <class T>
    class Type : public IType
    {
    public:
        T object;
        Type(T const& t)
        : object(t)
        {
        }
    };
    pIType itype;
public:
    template <class T>
    Variant& operator = (T const& t)
    {
        typedef Type<T> cType;
        itype = auto_ptr<cType>(new cType(t));
        return *this;
    }

    template <class T>
    operator T ()
    {
        typedef Type<T> cType;
        cType& type = dynamic_cast<cType&>(*itype);
        return type.object;
    }
};

class IBase
{
public:
  virtual Variant Get() = 0;
};

template <class T>
class A : public IBase
{
public:
  Variant value;
  A(){}
  A(T t)
  {
     value = t;
  }

  Variant Get()
  {
    return value;
  }
};

int _tmain(int argc, _TCHAR* argv[])
{
    vector<IBase*> v;
    
    v.push_back(new A<int>(100));
    v.push_back(new A<float>(8.9f));

    int i = v[0]->Get();
    float f = v[1]->Get();


    cout << i << endl;
    cout << f << endl;
    return 0;
}



PM MAIL   Вверх
Lazin
Дата 28.10.2009, 10:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(tilin @  28.10.2009,  09:42 Найти цитируемый пост)
Вот пример - код рабочий.

и бесполезный smile 

приходи, когда попробуешь написать реальный код, использующий этот класс, вопросы сразу возникнут, я гарантирую это smile 
PM MAIL Skype GTalk   Вверх
tilin
Дата 28.10.2009, 10:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(Lazin @ 28.10.2009,  10:04)
и бесполезный smile 

приходи, когда попробуешь написать реальный код, использующий этот класс, вопросы сразу возникнут, я гарантирую это smile

Вообще заморочки с Вариантом требовались для вполне реального кода, в продолжение поста Получение типа параметра функции. А нужно это все для того чтобы на автомате создавать объекты хранящие вызов функции вместе с параметрами и возвращаемым значением. Вот для получения возвращаемого значения из объекта хранящего вызов и потребовалось представить его Вариантом. Потому что такие объекты наследуются от абстрактного интерфейса и помещаются в вектор. Все прекрасно работает.
PM MAIL   Вверх
Lazin
Дата 28.10.2009, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(tilin @  28.10.2009,  10:25 Найти цитируемый пост)
Все прекрасно работает

пока ты знаешь тип возвращаемого значения
просто у тебя нет способа узнать тип значение, хранящегося в Variant-e, я уже несколько постов пытаюсь на это намекнуть smile 
Цитата(tilin @  28.10.2009,  10:25 Найти цитируемый пост)
Вообще заморочки с Вариантом требовались для вполне реального кода, в продолжение поста Получение типа параметра функции.

вообще, лень вникать, sry
просто, если у тебя не возникает необходимости определять тип значения, хранящегося в Variant-е, значит вероятно, тебе вообще не нужен Variant, ты просто усложнил архитектуру приложения smile 
PM MAIL Skype GTalk   Вверх
tilin
Дата 28.10.2009, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Нет, код который получает результат тип знает конечно. Как этот код выбирает объекты из контейнера - это другой вопрос. Но факт, что все объекты в контейнере должны иметь один тип, отсюда и наследование интерфейса, а из наличие в интерфейсе одного виртуального Get() на все наследуемые типы требует, чтобы Get() возвращал Вариант, который неявно преобразовывается к требуемому типу.
PM MAIL   Вверх
mes
Дата 28.10.2009, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Lazin @  28.10.2009,  09:32 Найти цитируемый пост)
просто, если у тебя не возникает необходимости определять тип значения, хранящегося в Variant-е, значит вероятно, тебе вообще не нужен Variant, ты просто усложнил архитектуру приложения smile 

 smile 
Цитата(tilin @  28.10.2009,  09:43 Найти цитируемый пост)
Но факт, что все объекты в контейнере должны иметь один тип, отсюда и наследование интерфейса, а

если тип объекта известен и помощь компилятора не требуется, то хранить объект можно и как void *

Цитата(tilin @  28.10.2009,  09:43 Найти цитируемый пост)
Как этот код выбирает объекты из контейнера - это другой вопрос. 

как раз от такого как происходит взаимодействие с элементом контейнера и зависит какой интерфейс должен поддерживать объект.


как я понимаю у Вас тип зависит от индекса, тогда

  если контейнер условно находится в библиотеке которая ничего не знает о типах, и предоставляет просто место для хранения, то тут как раз хранение по void* и каждый клиент имеет интерфейс по получению "готовых" объектов. 

  если же нужно хранить разношерстные элементы как одну структуру и все типы статически известные, то посмотрите например библиотечку boost::fusion в частности :
http://www.boost.org/doc/libs/1_40_0/libs/...ner/vector.html

В общем предположить что Вам требуется можно в разных вариантах и для каждого варианта нужен свой подход, поэтому, чтоб не гадать , было бы лучше если бы Вы полноценно осветили бы свое задание.








--------------------
PM MAIL WWW   Вверх
tilin
Дата 28.10.2009, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(mes @  28.10.2009,  11:59 Найти цитируемый пост)
как я понимаю у Вас тип зависит от индекса


Абсолютно не зависит. Объекты в массив добавляются в произвольной последовательности.

Цитата(mes @  28.10.2009,  11:59 Найти цитируемый пост)
если контейнер условно находится в библиотеке которая ничего не знает о типах, и предоставляет просто место для хранения, то тут как раз хранение по void* и каждый клиент имеет интерфейс по получению "готовых" объектов. 


В первом варианте Get() возвращал именно void*, потом клиент делал static_cast до нужного типа. Но мне хотелось, чтобы вместо 
Код
int i = (*static_cast<int*>(v[0]->Get()));

было
Код
int i = v[0]->Get();

Конечно использовать динамическое приведение типов вместо статического не есть Гут. И я еще подумаю, какой из них выбрать.
PM MAIL   Вверх
mes
Дата 28.10.2009, 12:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(tilin @  28.10.2009,  11:26 Найти цитируемый пост)
Абсолютно не зависит. Объекты в массив добавляются в произвольной последовательности.

так тип объекта с чем то связан или программист сам должен помнить под какой индекс что он добавил ?!

Цитата(tilin @  28.10.2009,  11:26 Найти цитируемый пост)
В первом варианте Get() возвращал именно void*, потом клиент делал static_cast до нужного типа. Но мне хотелось, чтобы вместо 

имхо, приведенной в этом топике информации недостаточно для совета.


--------------------
PM MAIL WWW   Вверх
tilin
Дата 28.10.2009, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Общая задача выглядит так:

Требовалось реализовать объект, хранящий указатель на объект некого класса, указатель на метод класса, параметры вызова и возвращаемое значение. Такие объекты формируются вместе с параметрами, помещаются в список вместе с метаданными. Список преобразовывается. Некоторые элементы перемещаются в начало, некоторые в конец и т.д. Затем по определенным условиям вызывается метод Call объектов. Возвращаемое значение сохраняется в объекте. Затем по метаданным ищется объект в списке и код получает результат вызова (точно зная его тип конечно).
PM MAIL   Вверх
bsa
Дата 28.10.2009, 17:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



tilin, правильно ли я тебя понял, тебе нужно создавать "задачу", которая в большинстве случаев выглядит как вызов: result = object->method(data)?
Если result всегда одного типа, то рекомендую обратить внимание на boost::bind (для создания "задач") и boost::function (для хранения "задач" в контейнере). Если разных типов, то еще и на boost::any.

например, у тебя есть метод int A::method(double x). Ты хочешь его поставить в очередь задач a->method(1.0), тогда boost::bind(&A::method, a, 1.0) создаст тебе объект, который можно вызывать так: o(). Чтобы этот объект чему-нибудь присвоить (пока нет auto из c++0x) можно использовать или шаблоны или boost::function: boost::function<int()> f = boost::bind(&A::method, a, 1.0). Теперь появился функциональный объект f, который можно вызвать так: f().

А вот это уже можно хранить в контейнере (для случая с any):
Код
struct Task {
   template<class Handler>
   Task(Handler handler) : handler_(handler), complete_(false) {}
   const boost::any& result() const { return result_; }
   bool complete() const { return complete_; }
   void operator()() {
       result_ = handler_();
       complete_ = true;
   }
private:
   boost::any result_;
   boost::function<boost::any()> handler_;
   bool complete_;
};


Это сообщение отредактировал(а) bsa - 28.10.2009, 17:43
PM   Вверх
tilin
Дата 28.10.2009, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(bsa @  28.10.2009,  17:37 Найти цитируемый пост)
tilin, правильно ли я тебя понял, тебе нужно создавать "задачу", которая в большинстве случаев выглядит как вызов: result = object->method(data)?
Если result всегда одного типа, то рекомендую обратить внимание на boost::bind (для создания "задач") и boost::function (для хранения "задач" в контейнере). Если разных типов, то еще и на boost::any.


Да надо создавать что-то типа задачи, которая хранит объект, метод, параметры вызова и возвращаемое значение. Однако результ может быть совершенно разного типа.
В сторону boost-а я уже начал смотреть, но пока с целью ознакомления только лишь.
Выложу свое решение, поправьте, если что не то сделал. Списки типов из библиотеки Loki. В Loki NullType.h заменено:

Код

typedef void NullType;
    //class NullType {};



Основная реализация такая:

Код

#include "loki/Typelist.h"

using namespace Loki;

class ICallObject
{
public:
    virtual void Call() = 0;
    virtual void SetReceiver(void* pObj) = 0;
    virtual ICallObject* Clone() = 0;
    virtual void* GetResult() = 0;
};

template <typename T, typename D, typename R, class C, int n>
class CallObject : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
    }

    ICallObject* Clone()
    {
        return new CallObject<>(*this);
    }

    void* GetResult()
    {
    
    }
};

template <typename T, typename D, typename R, class C>
class CallObject<T,D,R,C,0> : public ICallObject
{
public:
    T* pObject;
    D pFunc;
    
    R result;

    CallObject(T* _pObject, D _pFunc)
        :    pObject(_pObject), pFunc(_pFunc)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        result = (pObject->*pFunc)();
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,R,C,0>(*this);
    }

    void* GetResult()
    {
        return &result;
    }
};

template <typename T, typename D, class C>
class CallObject<T,D,void,C,0> : public ICallObject
{
public:
    T* pObject;
    D pFunc;
    
    CallObject(T* _pObject, D _pFunc)
        :    pObject(_pObject), pFunc(_pFunc)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        (pObject->*pFunc)();
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,void,C,0>(*this);
    }

    void* GetResult()
    {
        return 0;
    }
};

template <typename T, typename D, typename R, typename C>
class CallObject<T,D,R,C,1> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;

    R result;
    Tp1 p1;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        result = (pObject->*pFunc)(p1);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,R,C,1>(*this);
    }

    void* GetResult()
    {
        return &result;
    }
};

template <typename T, typename D, typename C>
class CallObject<T,D,void,C,1> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;
    
    Tp1 p1;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        (pObject->*pFunc)(p1);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,void,C,1>(*this);
    }

    void* GetResult()
    {
        return 0;    
    }
};


template <typename T, typename D, typename R, typename C>
class CallObject<T,D,R,C,2> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;
    typedef typename TL::TypeAt<C, 1>::Result Tp2;

    R result;
    Tp1 p1;
    Tp2 p2;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1, Tp2 _p2)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1), p2(_p2)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        result = (pObject->*pFunc)(p1, p2);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,R,C,2>(*this);
    }

    void* GetResult()
    {
        return &result;
    }
};

template <typename T, typename D, typename C>
class CallObject<T,D,void,C,2> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;
    typedef typename TL::TypeAt<C, 1>::Result Tp2;

    Tp1 p1;
    Tp2 p2;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1, Tp2 _p2)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1), p2(_p2)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        (pObject->*pFunc)(p1, p2);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,void,C,2>(*this);
    }

    void* GetResult()
    {
        return 0;
    }
};

#define CallObj(A,O,F,...) CallObject<A,\
    A::T##F##,\
    A::T##F##ReturnType,\
    A::T##F##Types,\
    TL::Length<A::T##F##Types>::value>\
    co(O, &A::##F, __VA_ARGS__);


#define SETTYPES(Class, FName, Return,...)\
    typedef Return (##Class##::*T##FName##)(__VA_ARGS__);\
    typedef TL::MakeTypelist<__VA_ARGS__>::Result T##FName##Types;\
    typedef Return T##FName##ReturnType; 


Макросы только для удобства записи.

Пример использования. Func6 для примера без использования макроса  SETTYPES:

Код

#include "CallObject.h"
#include <iostream>

using namespace std;

class A
{
public:

    SETTYPES(A,Func1, void, void)
    void Func1(void)
    {
    }

    SETTYPES(A,Func2, int, void )
    int Func2(void)
    {
        return 100;
    }

    SETTYPES(A,Func3, int, int)
    int Func3(int d)
    {
        return d;
    }

    SETTYPES(A,Func4, void, int)
    void Func4(int d)
    {
        
    }

    SETTYPES(A,Func5, int, int, float)
    int Func5(int d, float f)
    {
        return d+f;
    }

    typedef void (A::*TFunc6)(int, float);
    typedef TL::MakeTypelist<int, float>::Result TFunc6Types;
    typedef void TFunc6ReturnType;
    void Func6(int d, float f)
    {
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    CallObj(A, &a, Func5, 12,130);

    co.Call();
    int res = (*static_cast<int*>(co.GetResult()));
    cout << res << endl;

    return 0;
}

PM MAIL   Вверх
bsa
Дата 29.10.2009, 16:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



tilin, я тебе дал готовое решение, которое в разы проще и надежней твоего - используй его!

Забыл написать, как добавлять задачи. Допустим, есть менеджер задач, у которого есть метод добавления, объявленный так:
Код
template<class Handler>
void TaskManager::add(Handler handler);
То чтобы поставить на выполнение вызов:
Код
MyClass *object;
...
object->method(1.0, 2.0, "asdf");
 нужно написать:
Код
tm->add( boost::bind(&MyClass::method, object, 1.0, 2.0, "asdf") );


Кстати, начиная с версии 1.35 в boost уже есть менеджер задач! Вот только находится он в неочевидном месте и еще менее очевидно называется. Это boost::asio::io_service. Чтобы с ним работать нужно знать всего два метода: io_service::post() (постановка задачи на асинхронное исполнение), и io_service::run() (выполнение всех задач, пока они есть в очереди; может быть вызван одновременно в нескольких потоках, что приведет к параллельному исполнению задач).
PM   Вверх
Lazin
Дата 29.10.2009, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(bsa @  29.10.2009,  16:11 Найти цитируемый пост)
tilin, я тебе дал готовое решение, которое в разы проще и надежней твоего - используй его!
 smile 
а еще - функциональней, благодаря полиморфному поведению boost::function, в качестве задач можно использовать не толко ф-ии, но и методы и функторы, твой пример можно переписать вот так:

Код

...
#include <iostream>
using namespace std;
class A
{
public:
    void Func1(void)
    {
    }
    int Func2(void)
    {
        return 100;
    }
    int Func3(int d)
    {
        return d;
    }
    void Func4(int d)
    {  
    }
    int Func5(int d, float f)
    {
        return d+f;
    }
    void Func6(int d, float f)
    {
    }
};

class TaskManager
{
public:
    template<class H>
    void Add(H handler)
    {
         Task<H> task(handler);
         // сделать что-то с task, например:
         task();
         std::cout << task.result() << std::endl;
    }
    ...
};

int main(int argc, char* argv[])
{
    A a;
    boost::shared_ptr<A> p;
    p.reset(new A());
    TaskManager manager;
    manager.add( boost::bind<int>(&A::Func5, &a, 12, 130) );
    manager.add( boost::bind(&A::Func4, p, 42) );
    return 0;
}



Добавлено через 4 минуты и 51 секунду
Цитата(bsa @  28.10.2009,  17:37 Найти цитируемый пост)
struct Task {
   template<class Handler>
   Task(Handler handler) : handler_(handler), complete_(false) {}
   const boost::any& result() const { return result_; }
   bool complete() const { return complete_; }
   void operator()() {
       result_ = handler_();
       complete_ = true;
   }
private:
   boost::any result_;
   boost::function<boost::any()> handler_;
   bool complete_;
};

кстати, если нет желания использовать boost::asio::io_service, то можно просто сделать не шаблонный класс - наследник Task, у котрого был-бы определен виртуальный метод result, complete и operator() и работать с объектами Task - полиморфно

Код

class ITask
{
   virtual void operator () () = 0;
   ...
};

template<class Handler>
class Task : public ITask
{
...
};


Это сообщение отредактировал(а) Lazin - 29.10.2009, 16:47
PM MAIL Skype GTalk   Вверх
tilin
Дата 29.10.2009, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Все понял.
Честно, я понятия не имел, что если сделать вот так
Код

template <typename R, typename T, typename Arg>
void bind(R (T::*fn)(Arg), const T& t) 

а потом вот так
Код

bind(&A::Func, a);


То в bind будут автоматически определены типы. Я в шоке. Век живи - век учись )
PM MAIL   Вверх
bsa
Дата 29.10.2009, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(tilin @ 29.10.2009,  17:26)
Честно, я понятия не имел, что если сделать вот так
Код

template <typename R, typename T, typename Arg>
void bind(R (T::*fn)(Arg), const T& t) 

а потом вот так
Код

bind(&A::Func, a);

Решил свой аналог boost::bind сделать?  smile 
PM   Вверх
tilin
Дата 30.10.2009, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(bsa @  29.10.2009,  18:58 Найти цитируемый пост)
Решил свой аналог boost::bind сделать?  smile 

Просто очень хочется разобраться как делаются такие вещи  smile .
Вот что получяется. Я в правильном направлении?
Код

#include <iostream>


// ================================
class Base
{
public:
  virtual void Call() = 0;
  virtual void* GetResult() = 0;
};

template <typename R, typename T, typename Arg1, typename Arg2>
class CallObject : public Base
{
  typedef R (T::*TFunc)(Arg1, Arg2);
  TFunc func;
  T* object;
  R result;
  Arg1 ar1;
  Arg2 ar2;

public:
  CallObject(TFunc _func, T* _object, Arg1 _ar1, Arg2 _ar2) 
      : func(_func), object(_object) , ar1(_ar1), ar2(_ar2) 
  { }

  void Call()
  {
      result = (object->*func)(ar1,ar2);
  }
  void* GetResult()
  {
        return &result;
  }
};

template <typename R, typename T, typename Arg1, typename Arg2>
inline Base* CreateCallObject(
  R (T::*func)(Arg1, Arg2), 
  T* object, 
  Arg1 ar1,
  Arg2 ar2) 
{
  return new CallObject<R, T, Arg1, Arg2>(func, object, ar1,ar2);
}

// ================================


class A
{
public:
    float Func(int d, float f)
    {
        return d+f;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    Base* b = CreateCallObject(&A::Func, &a, 12, (float)24);
    b->Call();
    float res = *(static_cast<float*>(b->GetResult()));

    
    return 0;
}


PM MAIL   Вверх
mes
Дата 30.10.2009, 14:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(tilin @  30.10.2009,  12:12 Найти цитируемый пост)
Вот что получяется. Я в правильном направлении?

весь код не смотрел, но судя по этой строке :
Цитата(tilin @  30.10.2009,  12:12 Найти цитируемый пост)
  float res = *(static_cast<float*>(b->GetResult()));

имхо Вы держите путь в сторону.


Это сообщение отредактировал(а) mes - 30.10.2009, 14:27


--------------------
PM MAIL WWW   Вверх
tilin
Дата 30.10.2009, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(mes @  30.10.2009,  14:26 Найти цитируемый пост)
имхо Вы держите путь в сторону.

А вот если добавить сохранение результата в виде Варианта, тогда при получении значения руками преобразования типов делать не надо:
Код

float res = b->GetResult();

Только в моем варианте dynamic_cast пользуется, поэтому наверное стоит поучиться у boost::any  )

В общем вот так получается
Код

#include <memory>

using namespace std;

// ================================
class Variant
{
private:
    class IType
    {
    public:
        virtual ~IType()
        {
        }
    };
    typedef auto_ptr<IType> pIType;
    template <class T>
    class Type : public IType
    {
    public:
        T object;
        Type(T const& t)
        : object(t)
        {
        }
    };
    pIType itype;
public:
    template <class T>
    Variant& operator = (T const& t)
    {
        typedef Type<T> cType;
        itype = auto_ptr<cType>(new cType(t));
        return *this;
    }

    template <class T>
    operator T ()
    {
        typedef Type<T> cType;
        cType& type = dynamic_cast<cType&>(*itype);
        return type.object;
    }
};

class Base
{
public:
  virtual void Call() = 0;
  virtual Variant GetResult() = 0;
};

template <typename R, typename T, typename Arg1, typename Arg2>
class CallObject : public Base
{
  typedef R (T::*TFunc)(Arg1, Arg2);
  TFunc func;
  T* object;
  Variant result;
  Arg1 ar1;
  Arg2 ar2;

public:
  CallObject(TFunc _func, T* _object, Arg1 _ar1, Arg2 _ar2) 
      : func(_func), object(_object) , ar1(_ar1), ar2(_ar2) 
  { }

  void Call()
  {
      result = (object->*func)(ar1,ar2);
  }
  Variant GetResult()
  {
        return result;
  }
};



template <typename R, typename T, typename Arg1, typename Arg2>
inline Base* CreateCallObject(
  R (T::*func)(Arg1, Arg2), 
  T* object, 
  Arg1 ar1,
  Arg2 ar2) 
{
  return new CallObject<R, T, Arg1, Arg2>(func, object, ar1,ar2);
}

// ================================


class A
{
public:
    float Func(int d, float f)
    {
        return d+f;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    Base* b = CreateCallObject(&A::Func, &a, 12, (float)24);
    b->Call();
    float res = b->GetResult();

    return 0;
}

PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1089 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.