2013-04-20 3 views
0

Мне нужен общий способ создания экземпляра любого типа. нуждается Эта задача должна быть выполнена из не-шаблонного объекта, и поэтому я в настоящее время с помощью интерфейса, например так:Конструктор Аргумент переадресации через интерфейс

class Interface 
{ 
public: 
    virtual void PlacementCopy(void *data, const void *src) const = 0; 
    virtual void PlacementNew(void *data) const = 0; 
    virtual void PlacementDelete(void *data) const = 0; 
    virtual void Delete(void *data) const = 0; 
    virtual void Copy(void *dest, const void *src) const = 0; 
    virtual void NewCopy(void **dest, const void *src) const = 0; 
    virtual void *New() const = 0; 
}; 

Это все, кроме системы пользовательского отражения, и поэтому он используется, как это:

int *p = META(int)->Interface->New(); 
*p = 10; 

Это работает путем создания шаблонного объекта, который является производным от Interface, который содержит тип будет построена. New оператор в интерфейсе делает конструкцию по умолчанию типа:

template <typename T> 
class Derived : public Interface 
{ 
    virtual void *New(void) const override 
    { 
    return new T(); 
    } 
}; 

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

мне как-то нужно, чтобы быть в состоянии сделать:

MetaInfo *meta = META(SomeType); 
SomeType *object = meta->New(arg1, arg2); 

Что бы возможно искать что-то подобное в реализации:

template <typename T> 
Derived : public Interface 
{ 
    template <typename ... Args> 
    virtual void *New(Args&& ... args) const override 
    { 
    new T(std::forward<Args>(args) ...); 
    } 
}; 

Объект MetaInfo не шаблонный тип, который затрудняет придумайте решение для переадресации аргументов. Я не могу просто templatize метод New в классе Derived, так как вы не можете templatize виртуальный метод.

Является ли то, что я прошу даже без предварительной сумасшедшей предварительной обработки кода?

+0

Вы можете использовать генератор кода или препроцессор (скорее всего [Boost.Preprocessor] (http://www.boost.org/doc/ libs/1_53_0/libs/preprocessor/doc/index.html)) для создания безумного количества перегрузок для разных чисел и типов аргументов. – Angew

+0

Ха-ха, я бы предпочел не делать предварительную обработку кода, если это возможно. Не большой поклонник добавления шагов до сборки, если их можно избежать. Это усложняет процесс сборки и добавляет потенциал для непредвиденного обслуживания кода. – RandyGaul

+0

Что вы ожидаете, если ваш метаобъект описывает класс с одним конструктором, принимающим один аргумент 'int', а кто-то называет' meta-> New («thank you», 42.0) '? Должна ли быть ошибка времени компиляции, ошибка времени выполнения или что? –

ответ

0

В конце концов я собрал решение с помощью некоторых друзей!

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

struct HasDefaultCtor 
{ 
    template <typename U> 
    static int32 SFINAE(decltype(U()) *); 
    template <typename U> 
    static int8 SFINAE(...); 

    static const bool value = sizeof(SFINAE<T>(NULL)) == sizeof(int32); 
}; 

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

Я надеюсь, что это имеет смысл и в конечном итоге полезно для кого-то в будущем.

Я также сделал чек SNIFAE для конструктора копирования:

template <typename T> 
struct HasCopyCtor 
{ 
    static T MakeT(void); 

    template <typename U> 
    static int32 SFINAE(decltype(U(MakeT())) *); 
    template <typename U> 
    static int8 SFINAE(...); 

    static const bool value = sizeof(SFINAE<T>(NULL)) == sizeof(int32); 
}; 
+0

У C++ 11 уже есть те шаблоны признаков типов (см., Например, http://en.cppreference.com/w/cpp/types/is_default_constructible). – bluescarni

+0

Уверены, но у них нет проверки более продвинутых вещей, например, определенного количества аргументов. – RandyGaul

Смежные вопросы