traits类,名称空间和前向声明

时间:2019-01-18 16:08:14

标签: c++ design-patterns coding-style api-design generic-programming

我目前在使用带有traits类的名称空间时遇到麻烦。这是我的临时代码结构:

namespace project {

namespace internal {
template<typename T> struct traits;

} // internal

namespace moduleA {

namespace internal {

class AImpl {

using some_typeA = traits<A>::some_type;
using some_typeAImpl = traits<AImpl>::some_type;
// where to put the traits specialization?? How the forward declaration could be done?

};

} // internal

class A {

A(): imp(new internal::AImpl()) {}
private:
    internal::AImpl* imp;
};

} // moduleA

} // project

这是我的问题,我正在寻找建议,以使这些代码更好地遵循既定的惯例和最佳做法:

  1. 我正在定义两个内部命名空间::project::internal::project::moduleA::internal,这是不好的做法吗?我对此的担心是,由于具有两个级别,因此用户可以更轻松地从doxygen浏览文档,因为所有与moduleA相关的东西(无论moduleA :: internal和不是)都被组合在一起。
  2. 因为moduleA::internal::AImpl依赖于自身traits<AImpl>的特征类,而我的特征模板位于::project::internal中,所以我必须(1)在{{1中定义一个特征模板}}并对其进行专门化; (2)在moduleA::internal中定义特征特化。为此,我需要前向声明AImpl。对于情况(1)或(2),应如何精确地完成?这是否意味着我必须编写如下代码:
::project::internal

似乎我过多地使用了namespace project { namespace moduleA {class A;} namespace internal { template<> struct traits<module::A> {}; } namespace moduleA { ... // more code } } 子句。

  1. 类似于2,namespace {}取决于module::internal::AImpl,同样,我需要转发声明A,所以同样的问题。

非常感谢您的帮助,谢谢!

1 个答案:

答案 0 :(得分:1)

您可以使用函数声明(无需定义)来代替在C ++ 11中为特征使用类模板。可以使用argument-dependent name lookup找到函数,以便可以在声明类的同一名称空间中为类专门化特征。

这完全消除了必须关闭类的命名空间,打开traits命名空间,使用其完全限定名称为类专门化trait,关闭traits命名空间,重新打开类的命名空间的麻烦。并且也无需包含主模板的声明。

示例:

#include <type_traits>

template<class T> struct Type {};

template<class T>
void trait_of(Type<T>); // Generic trait version.

namespace N {
struct A;
int trait_of(Type<A>); // Trait specialisation for A.
} // N

int main() {
    using trait_of_a = decltype(trait_of(Type<N::A>{})); // trait_of is found using ADL.
    static_assert(std::is_same<int, trait_of_a>::value, "");
}

trait函数的返回类型可以是更多类型的容器,例如:

template<class T>
void more_traits(Type<T>); // Generic trait version. Must be specialized.

namespace N {
struct MoreTraitsOfA {
    using type_X = ...;
    using type_Y = ...;
};
MoreTraitsOfA more_traits(Type<A>); // Trait specialisation for A.
} // N

using MoreTraits = decltype(more_traits(Type<N::A>{})); 
using type_X = MoreTraits::type_X;
using type_Y = MoreTraits::type_Y;