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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Шаблоны. Тип класса по указателю на его метод, Получение типа класса из указателяметода 
:(
    Опции темы
DarkKnight
Дата 17.12.2013, 13:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Здравствуйте! Возникла необходимость получить тип класса, при передаче указателя на его метод в шаблонный класс. Такой вот код:
Код

// Интерфейс контейнера для хранения метода
class IMethodContainer 
        //: public boost::noncopyable
     { 
    public:
        IMethodContainer(){}
        virtual ~IMethodContainer(){}

        virtual void registerMethod(Binder& binder) = 0; 
    };

    // Контейнер для хранения указателя на метод
    template<class M, class T>
    class MethodContainer : public IMethodContainer
     {
    public:
        MethodContainer(M method, const QString& typeName, const QString& methodName)
            : _method(method)
            , _typeName(typeName)
            , _methodName(methodName)
        {
            Q_ASSERT_X(!_typeName.isEmpty(), "Object", "Type name could not be empty!");
            Q_ASSERT_X(!_methodName.isEmpty(), "Object", "Method name could not be empty!");
         }

         void registerMethod(Binder& binder)
        {
             binder.bindClassMethod<T, M>(_method, _typeName, _methodName);
         }

    private:            
        M _method;
        QString _typeName;
        QString _methodName;
     };

    // Интерфейс контейнера для хранения указателя на метод
    class IPtrContainer : public boost::noncopyable
     { 
    public:
        IPtrContainer(){}
        virtual ~IPtrContainer(){}

        virtual void createOject(Binder& binder) = 0;

    protected:
        boost::ptr_vector<wizard_detail::ILuaObjectMethodContainer*> _methodsContainer;
     };

    // Контейнер для хранения указателя на метод
    template<class T>
    class PtrContainer : public IPtrContainer
     {
    public:
        PtrContainer(T* obj, const QString& typeName, const QString& objName)
            : _object(obj)
            , _typeName(typeName)
             , _objName(objName)
        {
            Q_ASSERT_X(_object != NULL, "Object", "Object could not be null ptr!");
            Q_ASSERT_X(!_typeName.isEmpty(), "Object", "Type name could not be empty!");
            Q_ASSERT_X(!_objName.isEmpty(), "Object", "Object name could not be empty!");
         }

         void createOject(Binder& binder)
         {
            binder.createObject<T>(_object, _typeName, _objName);
         }

    private:            
        T* _object;
        QString _typeName;
         QString _objName;
        
    };
 }


    class Object : boost::noncopyable
    {
        public:
         template<class T>
        explicit Object(T* obj, const QString& typeName, const QString& objName)
        {
             set<T>(obj, QString(), typeName, objName);
        }

        template<class M>
        Object& addMethod(M method, const QString& name)
        {
            // <создается и сохраняется метод в _methodsContainer>
            return *this;
        }

        void bind(Binder& binder)
        {
            _container->registerMethod(binder);
        }

    private:
        template<class T>
        void set(T* obj, const QString& typeName, const QString& objName)
        {
            _ptrContainer.reset( new PtrContainer<T>(obj, typeName, objName) );
        }

    private:
        boost::scoped_ptr<IPtrContainer> _ptrContainer;
        boost::ptr_vector<IMethodContainer*> _methodsContainer;
    };



Собственно необходимо как-то заставить MethodContainer вычислять тип Т метода М(класса Т) при создании. Но как это сделать?

Это сообщение отредактировал(а) DarkKnight - 17.12.2013, 13:29
PM MAIL ICQ   Вверх
DarkKnight
Дата 17.12.2013, 14:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Есть вариант сделать абстрактный класс IObject, определив в нем необходимые общие методы, а Object унаследовать от IObject и сделать его полностью шаблонным. Я недавно только до этого додумался,к сожалению, и это работает =)
Но может быть кто-то все же знает как решить изначально поставленную задачу?

Это сообщение отредактировал(а) DarkKnight - 17.12.2013, 14:14
PM MAIL ICQ   Вверх
vinter
Дата 17.12.2013, 14:18 (ссылка) |   (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


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

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



Простейший вариант, в котором нужно задавать конструктор для каждой сигнатуры функции:
Код

#include <iostream>
#include <typeinfo>
using namespace std;


struct Container
{
    template<class T>
    Container(void (T::*)())
    {
        cout << typeid(T).name()  << "\n";
    }
};

class A
{
public:
    void foo()
    {

    }
};

int main()
{
    Container c(&A::foo);
    return 0;
}

С использованием C++11, позволят передавать функции любой сигнатуры:
Код

#include <iostream>
#include <typeinfo>
using namespace std;

struct Container
{
    template<class T, class Ret, class... Args>
    Container(Ret (T::*)(Args...))
    {
        cout << typeid(T).name()  << "\n";
    }
};

class A
{
public:
    void foo()
    {

    }
    int bar(int, char, std::iostream&)
    {
        return 0;
    }
};

int main()
{
    Container c(&A::foo);
    Container c1(&A::bar);
    return 0;
}


Как тебе это использовать? Тебе решать; можно сделать функцию-создатель твоего класса, можно еще как-то. Варианты есть, нужно просто выбрать подходящий.

P.S. А зачем тебе этот класс? std::function чем не устраивает?(или boost::function)


--------------------
Мой блог
PM MAIL WWW   Вверх
DarkKnight
Дата 17.12.2013, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



  Спасибо за решение, но к сожалению C++11 у нас нет, пишем под МСВС , там gcc 4.1.3, приходится забыть про auto, decltype и другие прелести) А вариант с конструктором для каждой сигнатуры функции не подходит, к сожалению =(
   Изначально я и хотел использовать boost::function, но не получилось, а все потому что мне нужно передавать в luabind тип класса, объект, и указатель на метод. Как я понял, boost::function оставляет тип класса где-то у себя в недрах, и получить его позже не получится. 
   И нужно, чтобы можно было забиндить любое количество методов объекта, и методы могут быть совершенно разные.
  Я в общем то решил проблему так,как писал выше, правда обнаружились другие, уже касательно самой luabind, но с ними вроде тоже разобрался - тестирую. 
  Интересует сам факт возможности решения задачи таким подходом, ведь мало ли где еще может пригодиться =) А в интернете к сожалению решения такого я не нашел..

Это сообщение отредактировал(а) DarkKnight - 18.12.2013, 09:37
PM MAIL ICQ   Вверх
akizelokro
Дата 17.12.2013, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


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

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



А corba у вас нет чтоли?


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
DarkKnight
Дата 18.12.2013, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(akizelokro @ 17.12.2013,  20:27)
А corba у вас нет чтоли?

Википедия говорит, что это стандарт написания распределенных приложений. Возможно я чего-то не понимаю, поясните пожалуйста, причем тут CORBA? У меня взаимосвязь между Lua и C++ происходит внутри одной библиотеки, на клиенте.
PM MAIL ICQ   Вверх
akizelokro
Дата 18.12.2013, 15:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


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

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



Цитата(DarkKnight @  18.12.2013,  09:29 Найти цитируемый пост)
Википедия говорит, что это стандарт написания распределенных приложений. Возможно я чего-то не понимаю, поясните пожалуйста, причем тут CORBA? У меня взаимосвязь между Lua и C++ происходит внутри одной библиотеки, на клиенте. 


Пардон, почитал немного и понял, что Lua уже использует Corba архитектуру и в ней есть LuaORB (брокер Corba). Corba это аналог COM-технологий. Точнее, наоборот, сначала стали развивать Corba, и лишь затем, кажется, ActiveX и COM. просто у тебя в задаче, как я понял, часть функционала, которую представляют эти технологиию А по Lua я не был в курсе и чёрт меня под локоть дёрнул свой вопрос написать  smile 




--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
DarkKnight
Дата 18.12.2013, 16:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(akizelokro @ 18.12.2013,  15:29)
Цитата(DarkKnight @  18.12.2013,  09:29 Найти цитируемый пост)
Википедия говорит, что это стандарт написания распределенных приложений. Возможно я чего-то не понимаю, поясните пожалуйста, причем тут CORBA? У меня взаимосвязь между Lua и C++ происходит внутри одной библиотеки, на клиенте. 


Пардон, почитал немного и понял, что Lua уже использует Corba архитектуру и в ней есть LuaORB (брокер Corba). Corba это аналог COM-технологий. Точнее, наоборот, сначала стали развивать Corba, и лишь затем, кажется, ActiveX и COM. просто у тебя в задаче, как я понял, часть функционала, которую представляют эти технологиию А по Lua я не был в курсе и чёрт меня под локоть дёрнул свой вопрос написать  smile

ничего страшного, зато я узнал интересную для себя информацию  smile  
PM MAIL ICQ   Вверх
Lukkoye
Дата 20.12.2013, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(DarkKnight @  17.12.2013,  15:18 Найти цитируемый пост)
И нужно, чтобы можно было забиндить любое количество методов объекта, и методы могут быть совершенно разные.



Если сигнатуры функций-методов целей заранее не известны, то можно:

1. Использовать механизм Connector, который не является шаболонном класса. (обычный класс). Поэтому, нет проблем хранить в массивах.
Динамический коннектор специально был разработан для решения подобных задач.

Умеет нацеливаться на любые функции или методы классов.
Пенальти: в дебаг-версии проверка на ошибки происходит в рантайме, что отражается на скорости работы.
в релиз-версии проверки не выполняются. Теряется безопасность.

2. Использовать boost::function/std::function. В связке с boost::any.

Так например, метод любой сигнатуры всегда можно привести к универсальному виду:
std::function<boost::any(boost::any)>
Пенальти: теряется контроль за ошибками времени компиляции. Медленно, и не экономично. Рекомендуется смотреть в сторону пункт 1.

Если сигнатура только одна и она заранее известна:
1. Использовать boost::function/std::function 
Пенальти: отсутствуют.


Если сигнатуры функций-методов целей известны заранее:
2. Использовать связку  boost::function/std::function и boost::variant
Пенальти: отсутствуют.
PM MAIL   Вверх
DarkKnight
Дата 22.12.2013, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(Lukkoye @ 20.12.2013,  22:33)
Цитата(DarkKnight @  17.12.2013,  15:18 Найти цитируемый пост)
И нужно, чтобы можно было забиндить любое количество методов объекта, и методы могут быть совершенно разные.



Если сигнатуры функций-методов целей заранее не известны, то можно:

1. Использовать механизм Connector, который не является шаболонном класса. (обычный класс). Поэтому, нет проблем хранить в массивах.
Динамический коннектор специально был разработан для решения подобных задач.

Умеет нацеливаться на любые функции или методы классов.
Пенальти: в дебаг-версии проверка на ошибки происходит в рантайме, что отражается на скорости работы.
в релиз-версии проверки не выполняются. Теряется безопасность.

2. Использовать boost::function/std::function. В связке с boost::any.

Так например, метод любой сигнатуры всегда можно привести к универсальному виду:
std::function<boost::any(boost::any)>
Пенальти: теряется контроль за ошибками времени компиляции. Медленно, и не экономично. Рекомендуется смотреть в сторону пункт 1.

Если сигнатура только одна и она заранее известна:
1. Использовать boost::function/std::function 
Пенальти: отсутствуют.


Если сигнатуры функций-методов целей известны заранее:
2. Использовать связку  boost::function/std::function и boost::variant
Пенальти: отсутствуют.

Спасибо за развернутый ответ.
Идеи, конечно, хорошие - не нужно будет городить свой огород из контейнеров для функторов и код в этом случае должен быть понятен тогда другим программистам, но:
1. Нет гибкости - продукт активно развивается, и проектов много. Иногда под какой то конкретный проект приходится что-то менять, и в этом случае повышались бы шансы изменения кода под определенные проекты, хотя это библиотека, которая не должна зависеть от проекта. Добавить пару сигнатур, конечно, не проблема, но все же..
2. Это compile-time, что не очень хорошо.

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

Я избавился от этих контейнеров, а просто создал класс и интерфейсы ILuaClassDef и LuaClassDef, в которых стал не хранить "голые" тип объекта и сигнатуру метода, а сразу создавать объект luabind::detail::class_base, и при каждом добавлении метода, добавлять его тут же в объект этого типа. LuaObject наследовал ILuaObject, а ILuaObject теперь хранил один лишь boost::scoped_pointer<ILuaClassDef> _classDef и имел друга Wizard. А биндер научился регистрировать объекты типа ILuaClassDef. В итоге Wizard отправлял приватный член _classDef объекта класса ILuaObject(так как был другом) в Binder, и тот регистрировал тип и создавал объект этого типа в Lua.


Интерес был в том, чтобы создать именно такой шаблон, который принимал бы на вход любой метод любого класса,и от него можно было бы получить тип самого класса. Просто ведь понятно, что у компилятора информация такая есть, впрос только как ее получить?
PM MAIL ICQ   Вверх
Lukkoye
Дата 22.12.2013, 20:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(DarkKnight @  22.12.2013,  00:40 Найти цитируемый пост)
Интерес был в том, чтобы создать именно такой шаблон, который принимал бы на вход любой метод любого класса,и от него можно было бы получить тип самого класса. Просто ведь понятно, что у компилятора информация такая есть, впрос только как ее получить?


От компилятора - никак. 

Все существующие на сегодняшний день механизмы разруливают этот момент с помощью шаблонов.
С появлением с++11 variadric templates это стало относительно не сложно.

Но если вам критична поддержка с++03, то вам придется реализовать шаблон с кучей специализаций под все возможные ситуации.

Например, механизм Connector для этих целей использует вспомогательный механизм Info_Function

Использование которого может быть вида:

Код

void template<class Method> Foo(Method method)
{
    //времени компиляции запрещаем все аргументы не являющиеся методами классов
    enum { is_method =  Info_Function<Method >::eIS_METHOD };
    LOKI_STATIC_CHECK(is_method ==1, EXPECTED_MEMBER_FUNCTION);

     //получаем класс, методом которого является аргумент
     typedef typename Info_Function<Method >::Class_t Class_t;

     cout<<"this method is: "<<typeid(Method ).name()<<endl;
     cout<<"class of this method is: "<<typeid(Class_t).name()<<endl;
}


Info_Function это шаблон, который имеет кучу специализаций под все возможные сигнатуры функций или методов в с максимальным количеством аргументов до 7 штук включительно.

Это достаточно объемный файл, хотя сам механизм очень простой, его идея:

Код

//свойства неопознанной функции
template<class Function>struct Info_Function
{
    typedef SEmpty Foo;
    typedef SEmpty Free;
    typedef SEmpty Protocol;
    enum { eIS_FREE = 0, eIS_METHOD = 0, eIS_CONST = 0, eIS_VOLATILE = 0, eIS_ELLIPSE = 0, eNUM_OF_ARG = 0 };
    typedef SEmpty Return_t; 
    typedef SEmpty Class_t; 
    typedef SEmpty Arg1;
    typedef SEmpty Arg2;
    typedef SEmpty Arg3;
    typedef SEmpty Arg4;
    typedef SEmpty Arg5;
    typedef SEmpty Arg6;
    typedef SEmpty Arg7;
    Info_Function(){ Gen_CTOR; }
   ~Info_Function(){ Gen_DTOR; }
    Gen_DEBUGTEST;
};
template<class R>struct Info_Function< R(*)()>
{
    typedef R(*Foo)();
    typedef R(*Free)();
    typedef R Protocol(void);
    enum{ eIS_FREE = 1, eIS_METHOD = 0, eIS_CONST = 1, eIS_VOLATILE = 0, eIS_ELLIPSE = 0, eNUM_OF_ARG = 0 };
    typedef R Return_t;
    typedef SEmpty Class_t;
    typedef SEmpty Arg1;
    typedef SEmpty Arg2;
    typedef SEmpty Arg3;
    typedef SEmpty Arg4;
    typedef SEmpty Arg5;
    typedef SEmpty Arg6;
    typedef SEmpty Arg7;
    Info_Function(){ Gen_CTOR; }
   ~Info_Function(){ Gen_DTOR; }
    Gen_DEBUGTEST;
};
template<class R,class A1>struct Info_Function< R(*)(A1)>
{
    typedef R(*Foo)(A1);
    typedef R(*Free)(A1);
    typedef R Protocol(A1);
    enum{ eIS_FREE = 1, eIS_METHOD = 0, eIS_CONST = 1, eIS_VOLATILE = 0, eIS_ELLIPSE = 0, eNUM_OF_ARG = 1 };
    typedef R Return_t;
    typedef SEmpty Class_t;
    typedef A1 Arg1;
    typedef SEmpty Arg2;
    typedef SEmpty Arg3;
    typedef SEmpty Arg4;
    typedef SEmpty Arg5;
    typedef SEmpty Arg6;
    typedef SEmpty Arg7;
    Info_Function(){ Gen_CTOR; }
   ~Info_Function(){ Gen_DTOR; }
    Gen_DEBUGTEST;
};



И так под все возможные ситуации для 7 аргументов включительно.

Другого способа в рамках с++03 не существует.

Если глянуть в тот же буст - там это разруливается при помощи boost.preproseccor.
Смысл тот же, только буковок меньше, и читабельность на нуле.


Это сообщение отредактировал(а) Lukkoye - 22.12.2013, 20:53
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
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.0867 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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