暂时'重置'#define中的命名空间

时间:2013-06-17 20:03:00

标签: c++ c++11 namespaces

我想知道是否有办法'重置'命名空间。我主要是问这个,因为我想使用define来专门化一些模板结构。

以下是我可能希望实现的简化示例:

namespace base {
    template<typename>
    struct my_traits;
}

// specialize base::my_traits for TYPE
// obviously, this does not work
#define MAKE_SPECIALIZED_TRAITS(TYPE)           \
    namespace ::base {                          \
        template<>                              \
        struct my_traits<TYPE> {                \
            typedef TYPE type;                  \
            enum { size = TYPE::size };         \
        };                                      \
    }

namespace spec {
    struct my_struct {
        enum { size = 3 };
    };

    MAKE_SPECIALIZED_TRAITS(my_struct)
}

这样的事情可能吗?如果是这样,我将如何实现?

3 个答案:

答案 0 :(得分:2)

一种有趣的技术,可能会使用覆盖和ADL来生成您的特征类。

这是伪代码,但它可能是这样的:

namespace base {
  // a template function you override in your OWN namespace to use this trick:
  template<typename T>
  void my_traits_mapping( T const& ) {};

  // SFINAE enabled internal my_traits.  if you have default traits, put them here:
  template<typename T, typename=void>
  struct my_traits_impl;

  // Detect if my_traits_mapping has been overriden for T, and if so inherit
  // my_traits_impl from its return value:
  template<typename T>
  struct my_traits_impl< T, typename std::enable_if< !std::is_same<
      void, decltype( my_traits_mapping( std::declval<T>() ) )
    >::value >::type >:
    decltype( my_traits_mapping( std::declval<T&>() ) )
  {};

  // you might want to put the above in its own sub-namespace, so as not to clutter
  // up your interface... if it is in details or aux, people will be less tempted to
  // directly mess with it.

  // forward my_traits<T> to the impl type above.
  template<typename T>
  struct my_traits : my_traits_impl<T> {};
}

我在T上使用ADL以my_traits_mapping的实例调用T,提取返回类型,并从中继承my_traits_impl(只要它不是't void)。

现在,您所做的只是创建一个函数my_traits,而不是专门化my_traits_mapping(X),它会在您自己的命名空间中返回一个traits类。评估my_traits<T>时,找到此函数,找到返回值,并使用其类型构建my_traits<T>

没有任何东西会离开你的namespace,但你神奇地将你的类型注入到特征系统中,而没有将任何东西注入特征namespace

摆脱宏中的namespacetemplate内容。相反,在my_traits_FOO命名空间中创建details类型,然后将details::my_traits_FOO my_traits_mapping( FOO const& )添加到您调用宏的命名空间中,该命名空间应与声明FOO的命名空间相同

答案 1 :(得分:1)

如果您不希望在命名空间中定义名称,那么冒着听起来重复的风险(并且不打算将问题轻描淡写),请不要在命名空间中定义它。

namespace spec {
    struct my_struct {
        enum { size = 3 };
    };
}
MAKE_SPECIALIZED_TRAITS(spec::my_struct)

顺便说一句,我在宏中省略了结束分号并将其放在使用宏的位置。这看起来对我来说更“正常”:

MAKE_SPECIALIZED_TRAITS(my_struct);

答案 2 :(得分:0)

这不起作用吗?

   #define MAKE_SPECIALIZED_TRAITS(TYPE)        \
        template<>                              \
        struct ::base::my_traits<TYPE> {        \
            typedef TYPE type;                  \
            enum { size = TYPE::size };         \
        };

更新:

我在测试中完成了这项工作:

namespace base {   template struct my_traits; }

#define MAKE_SPECIALIZED_TRAITS(TYPE)        \
    namespace base { \
      template<>                              \
      struct my_traits<TYPE> {        \
          typedef TYPE type;                  \
          enum { size = TYPE::size };         \
      }; \
    }

namespace spec {
  struct s {
    enum { size = 10 };
    int o;
  };

}

MAKE_SPECIALIZED_TRAITS(spec::s)