特征 class、命名空间和前向声明
traits class, namespace and forward declaration
我目前在使用具有特征 classes 的命名空间时遇到问题。这是我暂定的代码结构:
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
以下是我的问题,我正在寻找建议以使此代码更好地遵循既定惯例和最佳实践:
- 我正在定义两个内部命名空间,
::project::internal
和 ::project::moduleA::internal
,这是一种不好的做法吗?我对此的担心是,有了两个级别,用户可能更容易从 doxygen 浏览文档,因为所有与 moduleA 相关的东西,包括 moduleA::internal 和不相关的东西,都被组合在一起。
- 因为
moduleA::internal::AImpl
依赖于自身 traits<AImpl>
的特征 class,而我的特征模板位于 ::project::internal
,所以我必须 (1) 定义一个moduleA::internal
中的特征模板并对其进行专门化; (2) 在::project::internal
中定义特征特化。为此,我需要前向声明 AImpl。对于每种情况(1)或(2),究竟应该如何完成?这是否意味着我必须编写这样的代码:
namespace project {
namespace moduleA {class A;}
namespace internal {
template<>
struct traits<module::A> {};
}
namespace moduleA {
... // more code
}
}
看来我对 namespace {}
子句的使用太多了。
- 类似于2,
module::internal::AImpl
依赖于traits<A>
,我又需要转发声明A,所以同样的问题。
非常感谢您对此提供帮助,谢谢!
您可以使用函数声明(无需定义),而不是在 C++11 中使用 class 特征模板。可以使用 argument-dependent name lookup 找到函数,这样您就可以在声明 class 的同一名称空间中为 class 特化特征。
这完全消除了必须关闭 class 的命名空间的麻烦,打开 traits 命名空间,使用其完全限定名称为 class 专门化特征,关闭 traits 命名空间,重新打开 class 的命名空间。并且还消除了包含主模板声明的需要。
示例:
#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函数的return类型可以是更多类型的容器,例如:
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;
我目前在使用具有特征 classes 的命名空间时遇到问题。这是我暂定的代码结构:
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
以下是我的问题,我正在寻找建议以使此代码更好地遵循既定惯例和最佳实践:
- 我正在定义两个内部命名空间,
::project::internal
和::project::moduleA::internal
,这是一种不好的做法吗?我对此的担心是,有了两个级别,用户可能更容易从 doxygen 浏览文档,因为所有与 moduleA 相关的东西,包括 moduleA::internal 和不相关的东西,都被组合在一起。 - 因为
moduleA::internal::AImpl
依赖于自身traits<AImpl>
的特征 class,而我的特征模板位于::project::internal
,所以我必须 (1) 定义一个moduleA::internal
中的特征模板并对其进行专门化; (2) 在::project::internal
中定义特征特化。为此,我需要前向声明 AImpl。对于每种情况(1)或(2),究竟应该如何完成?这是否意味着我必须编写这样的代码:
namespace project {
namespace moduleA {class A;}
namespace internal {
template<>
struct traits<module::A> {};
}
namespace moduleA {
... // more code
}
}
看来我对 namespace {}
子句的使用太多了。
- 类似于2,
module::internal::AImpl
依赖于traits<A>
,我又需要转发声明A,所以同样的问题。
非常感谢您对此提供帮助,谢谢!
您可以使用函数声明(无需定义),而不是在 C++11 中使用 class 特征模板。可以使用 argument-dependent name lookup 找到函数,这样您就可以在声明 class 的同一名称空间中为 class 特化特征。
这完全消除了必须关闭 class 的命名空间的麻烦,打开 traits 命名空间,使用其完全限定名称为 class 专门化特征,关闭 traits 命名空间,重新打开 class 的命名空间。并且还消除了包含主模板声明的需要。
示例:
#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函数的return类型可以是更多类型的容器,例如:
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;