2013-02-22 4 views
5

Я не знаю, возможно ли это вообще, но этого я хотел бы достичь: в шаблоном классе я хотел бы использовать пространство имен параметра шаблона ,Динамическое использование пространства имен на основе параметра шаблона

например.

template<class P> 
class Foo 
{ 
    public: 
     Foo(); 
     virtual ~Foo(); 

     void doSomething(P&); 
     void doSomethingElse(); 

    protected: 
     // There I'm hardcoding "namespace1" but that's what I'd like to 
     // be possibly dynamic 
     // (I'm assuming template parameter P = namespace1::Type) 
     void method1(namespace1::Type1&); 
     ... 
     void methodN(namespace1::TypeN&); 
} 

// Again, supposing P == namespace1::Type then I want to be using namespace1 
// everywhere in the implementation... 
using namespace namespace1; 

template<class P> 
void Foo<P>::doSomething(P& parameter) 
{ 
    ... 
    Type1 type1 = P.getType1(); // There namespace1::Type1 is returned !! 
    method1(type1); 
    ... 
} 

template<class P> 
void Foo<P>::doSomethingElse() 
{ 
    ... 
    TypeN typen; // There I want to instanciate a namespace1::TypeN !! 
    ... 
} 

... 

Конечно, я не хочу, чтобы специализировать шаблон и обеспечить специальную реализацию для каждого возможного P значения, а также я хотел бы избежать прохождения всех типов как Type1 и TypeN в качестве параметров шаблона, так как я потенциально их много.

Возможно ли это?

Проект основан на C++ 3, любое решение для ускорения приветствуется.

Update

Будучи параметр шаблона P сам точно так же как любой TypeN параметра, это может быть правильный подход:

template<typename NAMESPACE> 
class Foo 
{ 
    typedef typename NAMESPACE::Parameter MyParameter; 
    typedef typename NAMESPACE::Type1 MyType1; 
    typedef typename NAMESPACE::Type1 MyTypeN; 
    ... 
} 
+0

Готовы ли вы добавить некоторые материалы в каждое пространство имен, которое может быть использовано? –

+1

Какова связь между 'P',' Type1' ... 'TypeN'. В некоторых случаях имеет смысл кодировать эти отношения в 'P' сам по вложенному типу. Затем вы можете просто использовать 'typename P :: Type1', и это будет разрешено для соответствующего' Type1' для 'P'. –

+1

Очень вероятно, что то, что вам нужно достичь, не требует такого решения. Можете ли вы объяснить, почему, по-вашему, вам это нужно? –

ответ

5

Да и №

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

template <typename T> struct Trait { typedef typename T::Secondary Secondary; }; 

template <typename X> 
struct Foo { 
    typedef typename Trait<X>::Secondary Secondary; 

    void foo(Secondary const& s); 
}; 

Нет, вы не можете вывести пространство имен и, следовательно, не может использовать it; но обратите внимание, как с помощью локального псевдонима (typedef ...) в классе нет необходимости.

+0

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

+0

Однако я не согласен с вами, когда вы говорите, что пространство имен не может быть выведено: ADL является своего рода выводом пространства имен, хотя вы не можете напрямую манипулировать пространством имен. –

+0

@ LucTouraille: для использования OP, запрошенный (назначение типов аргументов функции) с использованием ADL, будет довольно громоздким. –

0

Нет, это невозможно, но вы можете использовать уродливый файл макросов.

//my_class.inl 
template<TYPE_ARG> 
struct my_class_t<TYPE_ARG> 
{ 
    foo() 
    { 
     NS_ARG::bar(); 
    } 
} 

//my.h 
template<class T> 
struct my_class_t{}; 

#define TYPE_ARG T1 
#define NS_ARG std 
#include "my_class.inl" 

#define TYPE_ARG T2 
#define NS_ARG boost 
#include "my_class.inl" 

#undef TYPE_ARG 
#undef NS_ARG 

Таким образом, вы будете автоматизировать специализацию классов для разных пространств имен. Вам это действительно нужно? : О)

+1

Также вы можете захотеть упаковать все ваши типы в черты ...:) – kassak

0

Если вы готовы добавить структуру внутри каждого пространства имен, в котором перечислены все типы, вам нужно, вы можете рассчитывать на ADL, чтобы получить эту структуру в зависимости от параметра шаблона:

#include <iostream> 
#include <utility> 

namespace Foo_ns 
{ 
    struct T1 
    { 
     static void m() { std::cout << "Foo_ns::T1" << '\n'; } 
    }; 
    struct Foo {}; 

    // List of all the types you need from this namespace 
    struct Types 
    { 
     typedef Foo_ns::T1 T1;   
    }; 

    // dummy function needed for ADL   
    Types types(...); 
} 

namespace Bar_ns 
{ 
    struct T1 
    { 
     static void m() { std::cout << "Bar_ns::T1" << '\n'; } 
    }; 
    struct Bar {}; 

    struct Types 
    { 
     typedef Bar_ns::T1 T1; 
    }; 

    Types types(...); 
} 

template <typename T> 
void callMOnT1(const T &arg) 
{ 
    typedef decltype(types(std::declval<T>())) Types; // ADL kicks in 
    //typedef typename std::result_of<types(T)>::type Types; 
    Types::T1::m(); 
} 

int main() 
{ 
    callMOnT1((Bar_ns::Bar())); // Bar_ns::T1 
    callMOnT1((Foo_ns::Foo())); // Foo_ns::T1 
} 

К сожалению, это решение используя некоторые возможности C++ 11 (а именно decltype и declval). По какой-то причине мне не удалось заставить код работать с result_of, который присутствует в Boost (возможно, кто-то мог объяснить, почему код с result_of не компилируется?).

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