如何解决相互引用的C ++模板实例化
是否有一种方法可以允许两个或多个模板实例相互引用?
示例:
/* invalid C++ */
/* we suppose MyTemplate1 and MyTemplate2 are declared */
typedef MyTemplate1<MyInstance2> MyInstance1;
typedef MyTemplate2<MyInstance1> MyInstance2;
我想没有,仍然问我以防万一。
增加精度,我想实现这样的构造:
/* invalid C++ */
#include <iostream>
template <typename typeT> struct MyStruct1 {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
typeT::print(i - 1);
}
}
};
template <typename typeT> struct MyStruct2 {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
typeT::print(i - 1);
}
}
};
/* of course this is invalid,since you can't reference MyInstance2
before it is declared */
typedef MyStruct1<MyInstance2> MyInstance1;
typedef MyStruct2<MyInstance1> MyInstance2;
int main() {
MyInstance1::print(5);
return 0;
}
输出应为:
MyStruct1 : 5
MyStruct2 : 4
MyStruct1 : 3
MyStruct2 : 2
MyStruct1 : 1
MyStruct2 : 0
请注意,我并不是要实现类似的输出,而是要实现类似的构造,其中两个(或更多)模板实例相互引用 使用尽可能少的附加代码:相互引用实例化应该很容易。但是,对于这两个模板的实现代码,我不在乎它们是否复杂。
解决方法
这是至少提供正确输出的解决方案。虽然对于您的用例来说,这是否也是可行的解决方案还不是很清楚,但是也许它至少可以帮助您进一步澄清问题。
#include <iostream>
template <template <typename> typename TemplateT> struct TemplateType {
template <typename typeT>
static void print(unsigned i) {
TemplateT<typeT>::print(i);
}
};
template <typename typeT> struct MyStruct1 {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
typeT::template print<TemplateType<MyStruct1>>(i - 1);
}
}
};
template <typename typeT> struct MyStruct2 {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
typeT::template print<TemplateType<MyStruct2>>(i - 1);
}
}
};
typedef MyStruct1<TemplateType<MyStruct2>> MyInstance1;
int main() {
MyInstance1::print(5);
return 0;
}
,
一种方法是使用类向前声明:
template<typename T> class M
{
static int foo(int i) { return i ? T::foo(i - 1) : 0; }
};
struct A;
struct B;
struct A : M<B>{};
struct B : M<A>{};
完全不同的代码,但是您有递归。
,我终于找到了令人满意的构造,其中涉及使用tierce构造作为上下文来声明subs元素。对于任何人来说,这并不是强制性的最佳解决方案,我可能不得不对其进行一些调整以满足我的需求,但这是代码:
#include <iostream>
#include <type_traits>
template <typename K,typename T> struct TypePair {
typedef K key;
typedef T type;
};
template <typename Context,typename P0,typename... PN> struct TypeMap {
template <typename K> struct get {
typedef typename std::conditional<
std::is_same<typename P0::key,K>::value,typename P0::type::template actual<Context>,typename TypeMap<Context,PN...>::template get<K>::type>::type type;
};
};
struct TypeNotFound {};
template <typename Context,typename P> struct TypeMap<Context,P> {
template <typename K> struct get {
typedef
typename std::conditional<std::is_same<typename P::key,typename P::type::template actual<Context>,TypeNotFound>::type type;
};
};
/* defining a context to link all classes together */
template <typename... TN> struct Context {
template <typename K> struct Access {
typedef typename TypeMap<Context<TN...>,TN...>::template get<K>::type type;
};
};
/* templates we want to cross ref,note that context is passed as a parameter*/
template <typename ContextT,typename Id2> struct MyStruct1Actual {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
ContextT::template Access<Id2>::type::print(i - 1);
}
}
};
template <typename ContextT,typename Id1> struct MyStruct2Actual {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
ContextT::template Access<Id1>::type::print(i - 1);
}
}
};
/* wrappers to not have to always pass context when instancing templates */
template <typename type> struct MyStruct1 {
template <typename ContextT> using actual = MyStruct1Actual<ContextT,type>;
};
template <typename type> struct MyStruct2 {
template <typename ContextT> using actual = MyStruct2Actual<ContextT,type>;
};
/* Enum and dummy id,could simply use Enum actually,but using classes a Id
can prove to be more elegant with complex structures,expecially as it could be
used to automatically create pairs instead of having to precise Id */
enum Ids : int { Struct1,Struct2 };
template <Ids id> struct Id {};
// instancing all stuff withing context
// clang-format off
typedef Context<
TypePair< Id<Struct1>,MyStruct1< Id<Struct2> > >,TypePair< Id<Struct2>,MyStruct2< Id<Struct1> > >
> Ctx;
// clang-format on
typedef Ctx::Access<Id<Struct1>>::type S1;
int main() {
S1::print(5);
return 0;
}
缩短名称比Context或TypePair具有更多含义是强制性的,但想法就在这里。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。