模板实例化问题 [英] Template instantiation question

查看:66
本文介绍了模板实例化问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是来自

comp.lang.c ++的重新发布(略有修改)。为了得到一些回应而进行了调整。


我是使用Loki'的工厂,如_Modern C ++ Design_中所示,用于在具有多个处理器的嵌入式环境中传递
消息。我为
创建了一个课程政策,我希望这个政策可以自动地在适当的工厂注册课程:


//在某些头文件中...

#include< cassert>

#include" Loki / Singleton.h"

#include" Loki / Factory.h"

#include" Loki / TypeManip.h"

#include" Loki / static_check.h"


//要求:ConcreteClass必须实现静态方法GetID()

模板<类AbstractClass,类ConcreteClass>

类DefaultCreationPolicy
{

public:

static AbstractClass * Create()

{

//验证给定的类型实际上是超级和子类

STATIC_CHECK(

SUPERSUBCLASS(AbstractClass,ConcreteClass),

types_are_not_super_and_subclass

);


断言(m_registered);


返回新的ConcreteC lass;

}


static bool IsRegistered(){return m_registered; }


受保护:

DefaultCreationPolicy(){}

~DefaultCreationPolicy(){}


private:

typedef Loki :: SingletonHolder< Loki :: Factory< AbstractClass,int>

theFactory;


static const bool m_registered; //每个模板实例化一个

};


//用各自的工厂注册我们所有的子类。

//(请注意,这些静态成员出现在头文件中,因为

//它们本身就是模板。编译器将确保

//全局只有一个实例。)


模板< class AbstractClass,类ConcreteClass>

const bool

DefaultCreationPolicy< AbstractClass,ConcreteClass> :: m_registered

= DefaultCreationPolicy< AbstractClass,ConcreteClass> ::

theFactory :: Instance()。注册(

ConcreteClass :: GetID(),

ConcreteClass :: Create

);


我使用这样的代码:


模板< int id>

struct AssignID

{

static int GetID(){return id; }

};


struct MyBase

{

virtual~MyBase(){} < br $>
};


enum {DERIVED_1,DERIVED_2};


struct Derived1

:MyBase

,AssignID< DERIVED_1>

,DefaultCreationPolicy< MyBase,Derived1>

{};


struct Derived2

:MyBase

,AssignID< DERIVED_2>

,DefaultCreationPolicy< MyBase,Derived2>

{};


理论上,此代码应自动注册这些两个班级

与一个MyBase工厂,以便我可以使用工厂创建对象

像这样:


// .. 。


typedef Loki :: SingletonHolder< Loki :: Factory< MyBase,int> >

theFactory;


void Foo()

{

尝试

{

typedef std :: auto_ptr< MyBase> Ptr;

Ptr p1(theFactory :: Instance()。CreateObject(DERIVED_1));

Ptr p2(theFactory :: Instance()。CreateObject(DERIVED_2));

// ...使用p1和p2 ......

}

catch(const std :: exception& e)

{

std :: cerr<< e.what()<< std :: endl;

}

}


问题是,只需上面的代码,

DefaultCreationPolicy<>策略永远不会被Derived1或

Derived2实例化,因此调用Factory<> :: CreateObject()会抛出

,因为这些类没有注册。但是,如果我手动访问

这样的创建政策:


void Bar()

{

if(Derived1 :: IsRegistered()&& Derived2 :: IsRegistered())

{

Foo();

}

}


然后,Derived1和Derived2 *根据需要自动实例化并注册




任何人都可以解释为什么会发生这种情况并且可能会建议更好的方式来强制实例化这些类吗?我试图避免手动引用每个工厂可创建的类,因为在我的

实际代码中,必须这样做是一件烦恼 - 特别是三年

从现在开始,当我或其他人需要在MyBase中添加一些额外的

子类时,必须记得手动参考

创作政策。


干杯! --M

This is a repost (with slight modifications) from
comp.lang.c++.moderated in an effort to get some response.

I am using Loki''s Factory as presented in _Modern C++ Design_ for
message passing in an embedded environment with multiple processors. I
created a policy for classes, which, I had hoped, would automatically
register the class with the appropriate factory:

// In some header file...
#include <cassert>
#include "Loki/Singleton.h"
#include "Loki/Factory.h"
#include "Loki/TypeManip.h"
#include "Loki/static_check.h"

// Requirements: ConcreteClass must implement a static method GetID()
template<class AbstractClass, class ConcreteClass>
class DefaultCreationPolicy
{
public:
static AbstractClass* Create()
{
// Verify that the given types are actually super and sub classes
STATIC_CHECK(
SUPERSUBCLASS( AbstractClass, ConcreteClass ),
types_are_not_super_and_subclass
);

assert( m_registered );

return new ConcreteClass;
}

static bool IsRegistered() { return m_registered; }

protected:
DefaultCreationPolicy() {}
~DefaultCreationPolicy() {}

private:
typedef Loki::SingletonHolder<Loki::Factory< AbstractClass, int>
theFactory;

static const bool m_registered; // One per template instantiation
};

// Register all our subclasses with their respective factories.
// (Note that these static members appear in header file because
// they are themselves templates. The compiler will ensure that
// there is only one instance of each globally.)

template<class AbstractClass, class ConcreteClass>
const bool
DefaultCreationPolicy<AbstractClass,ConcreteClass> ::m_registered
= DefaultCreationPolicy<AbstractClass,ConcreteClass> ::
theFactory::Instance().Register(
ConcreteClass::GetID(),
ConcreteClass::Create
);

I use this code like this:

template<int id>
struct AssignID
{
static int GetID() { return id; }
};

struct MyBase
{
virtual ~MyBase() {}
};

enum { DERIVED_1, DERIVED_2 };

struct Derived1
: MyBase
, AssignID< DERIVED_1 >
, DefaultCreationPolicy<MyBase,Derived1>
{};

struct Derived2
: MyBase
, AssignID< DERIVED_2 >
, DefaultCreationPolicy<MyBase,Derived2>
{};

In theory, this code should automatically register these two classes
with a MyBase factory so that I can create objects using the factory
like this:

// ...

typedef Loki::SingletonHolder< Loki::Factory<MyBase, int> >
theFactory;

void Foo()
{
try
{
typedef std::auto_ptr<MyBase> Ptr;
Ptr p1( theFactory::Instance().CreateObject( DERIVED_1 ) );
Ptr p2( theFactory::Instance().CreateObject( DERIVED_2 ) );
// ... use p1 and p2 ...
}
catch( const std::exception& e )
{
std::cerr << e.what() << std::endl;
}
}

The problem is that, with just the code above, the
DefaultCreationPolicy<> policy never gets instantiated for Derived1 or
Derived2, and thus either call to Factory<>::CreateObject() will throw
because the classes are not registered. If, however, I manually access
the creation policy somewhere like this:

void Bar()
{
if( Derived1::IsRegistered() && Derived2::IsRegistered() )
{
Foo();
}
}

then, Derived1 and Derived2 *do* get instantiated and registered
automatically as desired.

Can anyone explain why this happens and perhaps suggest a better way of
forcing the instantiation of these classes? I was trying to avoid
manually referencing each of the factory-creatable classes, since in my
real code, it''s an annoyance to have to do so -- especially three years
from now when I or someone else will need to add some additional
subclasses to MyBase and will have to remember to manually reference
the creation policy.

Cheers! --M

推荐答案

mlimber写道:
mlimber wrote:
这是一个转贴(略有修改)来自<为了得到一些回应,我们正在使用Loki的工厂。我正在使用_Modern C ++ Design_中的Loki'工厂来实现嵌入式消息的传递具有多个处理器的环境。
This is a repost (with slight modifications) from
comp.lang.c++.moderated in an effort to get some response.

I am using Loki''s Factory as presented in _Modern C++ Design_ for
message passing in an embedded environment with multiple processors.



[snip]


BTW,Loki的代码可以在这里找到:
http://sourceforge.net/projects/loki-lib/


干杯! --M


[snip]

BTW, the code from Loki can be found here:

http://sourceforge.net/projects/loki-lib/

Cheers! --M




mlimber写道:

mlimber wrote:
这是一个转贴(略有修改)来自
comp.lang.c ++。为了得到一些回应而进行了调整。

我正在使用Loki的工厂,如_Modern C ++ Design_中所示,用于传递消息具有多个处理器的嵌入式环境。我为类创建了一个策略,我希望它会自动在适当的工厂注册该类:

//在某些头文件中......
#include< cassert>
#include" Loki / Singleton.h"
#include" Loki / Factory.h"
#include" Loki / TypeManip.h"
#include" Loki / static_check.h"


#include< iostream>

//要求:ConcreteClass必须实现静态方法GetID()
模板<类AbstractClass,类ConcreteClass> ;
类DefaultCreationPolicy
公共:
static AbstractClass * Create()
//
//验证给定的类型实际上是超类和子类
STATIC_CHECK(
SUPERSUBCLASS(AbstractClass,ConcreteClass),
types_are_not_super_and_subclass
);

断言(m_registered);

返回新的ConcreteClass;
}
静态bool IsRegistered(){return m_registered; }

protected:
DefaultCreationPolicy(){}
~DefaultCreationPolicy(){}

private:
typedef Loki :: SingletonHolder<洛基::工厂及LT; AbstractClass,int>


缺少>这里。

theFactory;

static const bool m_registered; //每个模板实例化一个
};

//将所有子类注册到各自的工厂。
//(请注意,这些静态成员出现在头文件中,因为
//它们本身就是模板。编译器将确保
//全局只有一个实例。)模板<类AbstractClass,类ConcreteClass>
const bool
DefaultCreationPolicy< AbstractClass,ConcreteClass> :: m_registered
= DefaultCreationPolicy< AbstractClass,ConcreteClass> ::
theFactory :: Instance()。注册(
ConcreteClass :: GetID(),
ConcreteClass :: Create
);

我用这段代码是这样的:

template< int id>
struct AssignID
{
static int GetID(){return id; }
};

struct MyBase
{
virtual~MyBase(){}
};

枚举{DERIVED_1 ,DERIVED_2};

struct Derived1
:MyBase
,AssignID< DERIVED_1>
,DefaultCreationPolicy< MyBase,Derived1>
{};

struct Derived2
:MyBase
,AssignID< DERIVED_2>
,DefaultCreationPolicy< MyBase,Derived2>
{};

理论上,此代码应自动将这两个类注册到MyBase工厂,以便我可以使用工厂创建对象
这样:

// ... typedef Loki :: SingletonHolder< Loki :: Factory< MyBase,int> >
theFactory;

void Foo()
{
尝试
{
typedef std :: auto_ptr< MyBase> Ptr;
Ptr p1(theFactory :: Instance()。CreateObject(DERIVED_1));
Ptr p2(theFactory :: Instance()。CreateObject(DERIVED_2));
// ..使用p1和p2 ......
catch(const std :: exception& e)
{st / :: ster :: cerr<< e.what()<< std :: endl;
}


问题在于,只需上面的代码,
DefaultCreationPolicy<>策略永远不会被Derived1或
Derived2实例化,因此对Factory<> :: CreateObject()的调用将抛出
因为类没有注册。但是,如果我手动访问这样的创建政策:

void Bar()
{
if(Derived1 :: IsRegistered()&& ; Derived2 :: IsRegistered())
{
Foo();
}
}
然后,Derived1和Derived2 *做*实例化,根据需要自动注册。

任何人都可以解释为什么会发生这种情况


编译器选择静态数据成员(也不是。例如,
DefaultCreationPolicy< MyBase,Derived1> :: m_register ed

调试器中的
会导致错误,除非我使用m_registered。

并且可能会建议一种更好的方法来强制实例化这些类?
This is a repost (with slight modifications) from
comp.lang.c++.moderated in an effort to get some response.

I am using Loki''s Factory as presented in _Modern C++ Design_ for
message passing in an embedded environment with multiple processors. I
created a policy for classes, which, I had hoped, would automatically
register the class with the appropriate factory:

// In some header file...
#include <cassert>
#include "Loki/Singleton.h"
#include "Loki/Factory.h"
#include "Loki/TypeManip.h"
#include "Loki/static_check.h"
# include <iostream>
// Requirements: ConcreteClass must implement a static method GetID()
template<class AbstractClass, class ConcreteClass>
class DefaultCreationPolicy
{
public:
static AbstractClass* Create()
{
// Verify that the given types are actually super and sub classes
STATIC_CHECK(
SUPERSUBCLASS( AbstractClass, ConcreteClass ),
types_are_not_super_and_subclass
);

assert( m_registered );

return new ConcreteClass;
}

static bool IsRegistered() { return m_registered; }

protected:
DefaultCreationPolicy() {}
~DefaultCreationPolicy() {}

private:
typedef Loki::SingletonHolder<Loki::Factory< AbstractClass, int>
Missing a > here.
theFactory;

static const bool m_registered; // One per template instantiation
};

// Register all our subclasses with their respective factories.
// (Note that these static members appear in header file because
// they are themselves templates. The compiler will ensure that
// there is only one instance of each globally.)

template<class AbstractClass, class ConcreteClass>
const bool
DefaultCreationPolicy<AbstractClass,ConcreteClass> ::m_registered
= DefaultCreationPolicy<AbstractClass,ConcreteClass> ::
theFactory::Instance().Register(
ConcreteClass::GetID(),
ConcreteClass::Create
);

I use this code like this:

template<int id>
struct AssignID
{
static int GetID() { return id; }
};

struct MyBase
{
virtual ~MyBase() {}
};

enum { DERIVED_1, DERIVED_2 };

struct Derived1
: MyBase
, AssignID< DERIVED_1 >
, DefaultCreationPolicy<MyBase,Derived1>
{};

struct Derived2
: MyBase
, AssignID< DERIVED_2 >
, DefaultCreationPolicy<MyBase,Derived2>
{};

In theory, this code should automatically register these two classes
with a MyBase factory so that I can create objects using the factory
like this:

// ...

typedef Loki::SingletonHolder< Loki::Factory<MyBase, int> >
theFactory;

void Foo()
{
try
{
typedef std::auto_ptr<MyBase> Ptr;
Ptr p1( theFactory::Instance().CreateObject( DERIVED_1 ) );
Ptr p2( theFactory::Instance().CreateObject( DERIVED_2 ) );
// ... use p1 and p2 ...
}
catch( const std::exception& e )
{
std::cerr << e.what() << std::endl;
}
}

The problem is that, with just the code above, the
DefaultCreationPolicy<> policy never gets instantiated for Derived1 or
Derived2, and thus either call to Factory<>::CreateObject() will throw
because the classes are not registered. If, however, I manually access
the creation policy somewhere like this:

void Bar()
{
if( Derived1::IsRegistered() && Derived2::IsRegistered() )
{
Foo();
}
}

then, Derived1 and Derived2 *do* get instantiated and registered
automatically as desired.

Can anyone explain why this happens
The compiler optmizes away a static data member (nor a function for
that matter) if it is not used. For example,

DefaultCreationPolicy<MyBase,Derived1>::m_register ed

in the debugger results in an error, unless I use m_registered.
and perhaps suggest a better way of
forcing the instantiation of these classes?




你必须强制编译器使用那个成员。由于这是
优化,我认为这是依赖于实现的。在Visual C ++

7.0上,这有效:


template< class Abstract,class Derived,int id>

struct a_concrete_class

:摘要,

AssignID< id>,

DefaultCreationPolicy<摘要,派生>

{

a_concrete_class()

{

DefaultCreationPolicy< Abstract,Derived> :: IsRegistered();

}

};


struct Derived1

:a_concrete_class< MyBase,Derived1,DERIVED_1>

{

Derived1()

{

}

};


请注意

1)我考虑了a_concrete_class中的所有内容(使其更容易)

2)Derived1有一个默认构造函数


那个''是我找到的最简单的解决方案。

Jonathan



You have to force the compiler to use that member. Since this is
optimization, I think this is implementation dependent. On Visual C++
7.0, this works:

template <class Abstract, class Derived, int id>
struct a_concrete_class
: Abstract,
AssignID<id>,
DefaultCreationPolicy<Abstract, Derived>
{
a_concrete_class()
{
DefaultCreationPolicy<Abstract, Derived>::IsRegistered();
}
};

struct Derived1
: a_concrete_class<MyBase, Derived1, DERIVED_1>
{
Derived1()
{
}
};

Note that
1) I factored everything in a_concrete_class (to make it easier)
2) Derived1 has a default constructor

That''s the simplest solution I found.
Jonathan


mlimber写道:
mlimber wrote:
任何人都可以解释为什么会发生这种情况,也许可以建议一个更好的方式来赚钱

只生成您使用的模板的那些部分。这是一个很好的东西,因为它可以减少臃肿。在某些情况下,无法生成模板的某些特征。


假设您在类型< T>上对某些模板类TC进行了参数化。并且

它包含一些函数foo(),它的主体假定它可以调用

T :: bar()。现在,您在没有bar()函数的类T

上实例化该模板。如果你不使用foo(),这没关系!由于

foo()未被调用,因此模板< class T> TC :: foo的();永远不会生成,

所以对不存在的bar()的调用不是问题。


在你的情况下有一个棘手的问题,因为一个静态成员

变量正在被优化掉,但是这个静态成员变量有一个非平凡的初始化器,一个函数调用。并且你依靠那个

函数调用来做一些重要的事情。哎呀!

强制实例化这些类?


也许明确的模板实例化语法可以为你实现

。选择一些你想要模板的翻译单元

实例化生活和执行:


模板类X< A,B,...> ;;


其中X是模板类,A,B,...是你想要生成实例化的模板参数

类型。 />

显式实例化请求将生成整个模型

模板。


拆分它是个好主意模板分为两个头文件。一个

声明模板类和任何内联函数,一个

实现非内联函数和静态成员。


选择要实例化它的位置,在那里包含所有

参数类型,并输入所有实例化请求。为了减少编译依赖性,你可以为

引入多个模块来实例化不同类型的相同模板。即假设你想要为10个

不同的类实例化一个单参数模板
。您可以在一个地方包含所有十个这些类的声明和模板的定义,并且

在那里写入十个实例化请求。但是当你触摸任何一个类时,该模块将不得不重新编译。

我试图避免手动引用每个工厂可创建的类因为在我的真实代码中,这是一件令人烦恼的事情 - 特别是三年
从现在开始,当我或其他人需要添加一些额外的
子类时MyBase并且必须记住手动引用创建策略。


使用这个显式实例化的东西,你可以设置它,以便如果有人添加新类,但是没有添加,那么

编译将会失败

实例化请求。


如何?好吧,例如你的类有构造函数。你实际上从这些模板类继承了

,并且实现了

派生对象。


如果你给模板一个非 - 内联构造函数,模板

定义不包含在程序中并受一些隐式的

或显式实例化的影响,那么构造函数就不存在了

程序不会链接。


说到哪,你不能把m_registered的引用放到
$ b中$ b模板'的构造函数?


模板<类AbstractClass,类ConcreteClass>

类DefaultCreationPolicy

{

public:

//这个怎么样!!

DefaultCreationPolicy()

{

(void)IsRegistered(); //触摸那个静态成员

}


static AbstractClass *创建()

// ......等等。 br />

由于构造函数在某个地方被调用,它在IsRegistered中拖入依赖关系





{

//确认给定的类型实际上是超级和子类



干杯! --Mon
Can anyone explain why this happens and perhaps suggest a better way of
Only those parts of a template get generated that you use. This is a
nice thing because it reduces bloat. In some cases, certain features of
a template cannot be generated.

Suppose you have some template class TC parametrized on a type <T> and
it contains some function foo() whose body assumes that it can call
something T::bar(). Now you instantiate that template over a class T
which has no bar() function. That is okay if you don''t use foo()! Since
foo() isn''t called, template <class T> TC::foo(); is never generated,
and so the call to nonexistent bar() isn''t an issue.

In your case there is a tricky problem, because a static member
variable is being optimized away, but that static member variable has a
non-trivial initializer, a function call. And you are depending on that
function call to do something important. Oops!
forcing the instantiation of these classes?
Maybe the explicit template instantiation syntax will do the trick for
you. Pick some translation unit where you want the template
instantiation to live and do:

template class X<A, B, ...>;

where X is the template class, and A, B, ... are the template parameter
types for which you want ot generate the instantiation.

The explicit instantiation request will generate the whole darn
template.

It''s a good idea to split the template into two header files. One which
declares the template class and any inline functions, and one which
implements the noninline functions, and static members.

Pick a place where you want to instantiate it, include all the
parameter types there, and put in all the instantiation requests. To
reduce compile dependencies, you can introduce multiple modules for
instantiating the same template over different types. I.e. suppose you
wanted to instantiate a one-parameter template ten times for ten
different classes. You could include the declarations of all ten of
those classes and the definition of the template in one place, and
write ten instantiation requests there. But that module would have to
be recompiled whenever you touch any of those classes.
I was trying to avoid
manually referencing each of the factory-creatable classes, since in my
real code, it''s an annoyance to have to do so -- especially three years
from now when I or someone else will need to add some additional
subclasses to MyBase and will have to remember to manually reference
the creation policy.
With this explicit instantiation stuff, you can set it up so that the
compilation will fail if someone adds new classes, but doesn''t add the
instantiation requests for them.

How? Well, for instance your classes have constructors. You are
actually inheriting from these template classes, and instatiating the
derived objects.

If you give the template a non-inlined constructor, and the template
definition isn''t included in the program and subject to some implicit
or explicit instantiation, then the constructor won''t exist and the
program won''t link.

Speaking of which, can''t you put the reference to m_registered into the
template''s constructor?

template<class AbstractClass, class ConcreteClass>
class DefaultCreationPolicy
{
public:
// How about this!!
DefaultCreationPolicy()
{
(void) IsRegistered(); // touch that static member
}

static AbstractClass* Create()
// ... etc ..

Since the constructor is called somewhere, it drags in the dependency
on IsRegistered.


{
// Verify that the given types are actually super and sub classes


Cheers! --Mon






这篇关于模板实例化问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆