基于模板参数的动态命名空间使用

时间:2013-02-22 14:12:36

标签: c++ templates boost namespaces typedef

我不知道这是否可行,但这是我想要实现的:在模板化的类中,我想使用模板参数的命名空间。

例如。

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和{{ 1}}作为模板参数,因为我可能有很多。

这可能吗?

该项目基于C ++ 3,欢迎任何提升解决方案。

更新

作为模板参数TypeN本身与任何P参数完全相同,这可能是正确的方法:

TypeN

3 个答案:

答案 0 :(得分: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);
};

不,你不能推断名称空间,因此不能使用它;但请注意如何在类中使用本地别名(typedef ...),而不需要。

答案 1 :(得分: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

这样,您将为不同的命名空间自动化类专门化。你真的需要这个吗? :O)

答案 2 :(得分: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特性(即decltypedeclval)。出于某种原因,我没有设法让代码与result_of一起使用,它存在于Boost中(可能有人可以解释为什么带有result_of的代码无法编译?)。