C ++ сохраняет параметр шаблона как переменную - PullRequest
2 голосов
/ 17 января 2012

Я пишу универсальный класс-обертку для группы классов, которые мы определили в другом коде. Я пытаюсь выяснить, есть ли способ в C ++ написать шаблонный класс, который может хранить параметр шаблона в виде переменной. Вот пример того, что я хотел бы видеть на работе:

template < class C > class generic {
    public:
        C obj; // used for custom type processing

        template < class T > T other; // <- changeable variable (or something)

        template < class T > setOther() { // Function to change variable
            // code to change variable type, or set type
        }

        void doSomethingWithOther() {
            // do some processing for other, like call
            // specific member function or something
            (((other*)obj)->*SomeGenericMethod)()
        }
}

int main(int argc, char **argv) {
    Bar bObj;
    generic<Foo> fObj;
    fObj.setOther<Bar>();
    fObj.doSomethingWithOther();
    return 0;
}

Я знаю, что приведенный выше код не будет компилироваться по многим причинам, но мой вопрос больше касается функциональности. Есть ли какой-нибудь способ, которым я мог бы сохранить параметр шаблона как переменную (или использовать функцию или что-то), который затем мог бы использоваться позже как спецификатор типа? Если нет стандартного способа, какие-нибудь идеи от сообщества SO, которые могли бы привести к моим желаемым результатам?

Пожалуйста, не используйте Boost или другие сторонние библиотеки, я стараюсь сохранить его как "STL" (C99).

Другая идея, которая у меня возникла, заключалась в использовании специализаций по умолчанию:

template < class C, class T = void* > class generic {
    public:
        C obj;
        T other;
        // ... more code
}

но в этом случае, предполагая, что у нас было следующее:

class Test1 {
    public:
        generic<Foo> *G1;
        generic<Foo, Bar> *G2;
};

Если бы я захотел позже изменить тип G1 для выполнения какой-либо другой обработки, я мог бы сказать что-то вроде следующего:

G1 = new generic<Foo, Bar>(); // compile error, different types

Однако это приведет к ошибке компиляции, поскольку указанные два типа имеют разные типы (G1 имеет тип generic< C >, другой тип generic< C, T >, хотя класс шаблона T по умолчанию равен void*.

Извините за длинный пост, я пытаюсь быть максимально понятным в своих намерениях с этим кодом. Также, пожалуйста, не стесняйтесь поправлять меня в любом из моих утверждений выше (долгие дни = меньше активности мозга для меня)

Заранее благодарим за любую помощь в этом вопросе.

Редактировать 1:

Для пояснения, элемент данных other просто показывает, что я хотел бы, чтобы этот элемент содержал тип класса. Это связано с тем, что в нашем коде есть члены других классов, вызывающих инстансированные функции-члены. И если я сделаю вызов функции-члена другого класса, я получу ошибку компиляции.

И, к сожалению, я не могу использовать какие-либо функции C ++ 0x, поскольку наши встроенные компиляторы устарели и не поддерживают набор функций 0x. В противном случае это было бы очевидным решением.

По сути, мне нужно встроить систему делегированного типа, чтобы экземпляры классов могли вызывать члены других экземпляров классов изнутри себя, а вызываемая функция-член будет иметь пространство памяти и доступ к указателю this

.

Пример:

class Foo {
    public:
        Delegate other;
}

class Bar {
    public:
        void SomeFunction() {
            std::cout << "hello from Bar::SomeFunction, data = " << data << std::endl;
        }

        int data;
}

int main() {
     Foo F;
     Bar B;
     B.data = 10;
     F.other = Delegate::attach<Bar>(&Bar::SomeFunction, &B);
     // Delegate::attach is defined as 
     // template < class T > Delegate attach(void (T::*fnPtr)(void*), T *obj)
     F.other();
}

В приведенном выше примере void operator()() класса Delegate затем вызывает функцию других членов через (*fnPtr)(). Если вызывается таким образом, функция не имеет доступа к данным своего члена (не знает указатель this). Если вызывается с передачей ссылочного объекта (т.е. (*fnPtr)(obj)), функция теперь имеет доступ к данным члена.

Я пытаюсь решить эту проблему, указав универсальный объект class type, который затем можно приводить туда-сюда, так как Delegate other может присоединиться к любому члену.

Ответы [ 3 ]

4 голосов
/ 17 января 2012

Непонятно, в чем проблема, которую вы пытаетесь решить.В вашем коде, какова цель class C?Во всяком случае, вот предположение, что вы хотите.Используйте базовый шаблонный класс implementation, который наследуется от общего базового класса с виртуальным interface, а класс generic содержит указатель на этот interface.

class generic {
    class interface {
    public:
        virtual ~interface(){}
        virtual void SomeGenericMethod()=0;
    };
    template <class T>
    class implementation: public interface {
        T data;
    public:
        implementation(const T& d) :data(d) {}
        virtual void SomeGenericMethod() 
        {return data.SomeGenericMethod();}
    };
    public:
        std::unique_ptr<interface> data;

        template < class T > void setOther(const T& other) {
            data.reset(new implementation<T>(other));
        }

        void doSomethingWithOther() {
            data->SomeGenericMethod();
        }
};

int main(int argc, char **argv) {
    generic fObj;
    Bar bObj;
    fObj.setOther(bObj);
    fObj.doSomethingWithOther();
    return 0;
}

http://ideone.com/A1Aqu

0 голосов
/ 17 января 2012

Похоже, ваша главная цель - вызвать функцию-член other.

Если это так, вам даже не нужен other, а просто функтор, который инкапсулирует вызов. Например. с C ++ 11 или TR1:

template <class C> struct A {
    C obj;
    std::function<void ()> op;
    void f() {
        // ...
        op();
    }
};

struct B {
    void g() { std::cout << "moo" << std::endl; }
};

int main() {
    A<int> a;
    B b;
    a.op = std::bind(&B::g, &b);
    a.f();
}
0 голосов
/ 17 января 2012

Если вы не знаете точный тип во время компиляции, вы не можете закодировать его как параметр шаблона.Они должны быть известны во время компиляции и не могут быть изменены после этого.Проверьте Boost.Any (любой возможный тип) или Boost.Variant (несколько известных типов) для примеров, которые могут вам помочь.any реализуемо с разумными усилиями, variant не так много.Учитывая ваши знания о шаблонах C ++, вы, возможно, не должны пытаться реализовать их без реального понимания кода в надстройке, без обид.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...