C++ 具有调用者的模板函数';什么是背景?
考虑以下代码片段C++ 具有调用者的模板函数';什么是背景?,c++,C++,考虑以下代码片段 template <T> MyPtr<T> CreateObject() { // Do something here first... // return our new object return MyPtr<T>(new T()); } class Foo { private: Foo() { } public: static MyPtr<Foo> GetNewInstance(
template <T>
MyPtr<T> CreateObject()
{
// Do something here first...
// return our new object
return MyPtr<T>(new T());
}
class Foo
{
private:
Foo() { }
public:
static MyPtr<Foo> GetNewInstance()
{
// ERROR: Foo is private...
return CreateObject<Foo>();
}
};
class Bar
{
public:
Bar() { }
};
int main()
{
MyPtr<Bar> bar = CreateObject<Bar>();
return 0;
}
模板
MyPtr CreateObject()
{
//先在这里做点什么。。。
//返回我们的新对象
返回MyPtr(新的T());
}
福班
{
私人:
Foo(){}
公众:
静态MyPtr GetNewInstance()
{
//错误:Foo是私有的。。。
返回CreateObject();
}
};
分类栏
{
公众:
Bar(){}
};
int main()
{
MyPtr bar=CreateObject();
返回0;
}
在不使用CreateObject宏的情况下(我喜欢MyPtr obj=CreateObject(params)
的语法),是否有办法使函数CreateObject与调用函数共享相同的上下文,从而能够访问私有的Foo c'tor“friend”不是我想要的,因为它意味着任何调用CreateObject的人都可以访问私有的Foo c'tor,这不是我想要的。重载新操作符也不起作用,因为必须返回MyPtr,而不是仅仅返回t*(通过将t*分配给MyPtr,将一个类型分配给其他地方所需的对象)
我想我要找的是介于宏和模板函数之间的东西(模板函数的语法,但会像宏一样完全展开)。在这种特殊情况下,使用此功能将非常有用。这与基本相同
唯一允许这样做的方法是使用
friend
。很抱歉,您在这种情况下几乎陷入困境。因为您是新的
对象,所以它实际上与CreateObject
函数无关。因此,将功能原型更改为:
template <typename T>
MyPtr<T> CreateObject(T* const p)
{
//...
return MyPtr<T>(p);
}
模板
MyPtr CreateObject(T*const p)
{
//...
返回MyPtr(p);
}
用法:
static MyPtr<Foo> GetNewInstance()
{
return CreateObject(new Foo());
}
static MyPtr GetNewInstance()
{
返回CreateObject(新的Foo());
}
好吧,您可以通过以下方式实现:
有没有办法使函数CreateObject与调用方函数共享相同的上下文
是,将所需的上下文作为参数传递(作为模板的参数,或作为函数的参数)
实际上,将newt
调用移动到一个单独的函数(或结构模板,我在这里选择这样做),如下所示:
// Dummy representation of your pointer type
template <typename T>
struct MyPtr
{
MyPtr( T *p ) { }
};
// Default constructor template; may be specialized to not use "new" or so.
template <typename T>
struct Constructor
{
static T *invoke() { return new T; }
};
// Needs to be a struct (or class) so 'C' can have a default value
template <typename T, typename C = Constructor<T> >
struct CreateObject
{
MyPtr<T> operator()() {
return MyPtr<T>( C::invoke() );
}
};
class Foo
{
private:
friend struct Constructor<Foo>;
Foo() { }
public:
static MyPtr<Foo> GetNewInstance()
{
return CreateObject<Foo>()();
}
};
// ...
static MyPtr<Foo> GetNewInstance()
{
Constructor<Foo> c( arg1, arg2, arg3 );
return CreateObject<Foo>( c );
}
我不知道你想达到什么目的。把这个问题简化到这里,已经消除了对整个问题的实际需要。所以我假设你知道你在做什么,你真的需要它(我建议你重新考虑你是否真的需要它,因为我看不出有什么意义…) 无论如何,您都可以通过将创建者回调传递给
CreateObject
模板来解决此问题:
template <typename T, typename Creator>
MyPtr<T> CreateObject( Creator creator )
{
// Do something here first...
return MyPtr<T>(creator());
}
class Foo
{
private:
Foo() {}
static Foo* create() { return new Foo(); }
public:
static MyPtr<Foo> GetNewInstance() {
return CreateObject<Foo>( &Foo:create );
}
// ...
};
模板
MyPtr CreateObject(创建者)
{
//先在这里做点什么。。。
返回MyPtr(creator());
}
福班
{
私人:
Foo(){}
静态Foo*create(){返回新的Foo();}
公众:
静态MyPtr GetNewInstance(){
返回CreateObject(&Foo:create);
}
// ...
};
然而,实际的问题是,在这里首先要做的事情实际上是迫使你进入这个复杂的创建模式。它必须在创建新对象之前执行,这一事实似乎表明,代码中没有显示隐藏的依赖项,这通常会导致维护噩梦,在维护噩梦中,有人对某些代码重新排序,或添加新的构造函数,而所有东西似乎都崩溃了。重新审视你的设计并考虑这些依赖关系是否可以简化或明确化。这正是
friend
的用意。如何在没有访问其构造函数的情况下创建对象?是什么阻止您实现Foo::GetNewInstance()
asreturn new MyPtr(new Foo())
?。我看不出CreateObject()
在这里有多大意义,真的。就像我在OP中说的,我不希望CreateObject的调用方能够访问Foo,除非它在Foo本身中…@lasrm:很明显,示例代码就是为了说明我所面临的问题。@Xeo:就像我说的,在标准中有这个特性是非常有用的——正如我的OP所解释的那样。C++语言中的另一个限制。哦,正如我所想的那样。“扎克看到了——我相信你可以只做函数的一个实例化,即代码<朋友>代码>。看到有明显的真正需要使用这个特性的用例,C++委员会知道这个缺点吗?”Chris Lutz:精心设计?就像我在OP中说的,我不希望CreateObject的调用者能够访问Foo,除非它在Foo本身内…@Zach:我认为这种事情非常罕见,我不知道如何真正解决它。C++已经被频繁地擦除,因为它首先允许任何代码如<代码>朋友>代码。这比你在几乎所有其他OO语言中得到的都多…难道不是Foo
构造函数私有吗?@ZachSaw,你的//做点什么…
与新的t()无关。因此,您可以将其传递到外部。请参阅我编辑的帖子。@iammilind:它必须出现在新T()之前——因此,//首先在这里做点什么
@Zach,至少从您的代码来看,您似乎没有做任何会影响新T()
(最后是简单的分配)。如果您在问题中编写了伪代码,那么我的答案不适用。否则,我的指导是正确的。你也可以这样想,“无论你在CreateObject()的开头还是结尾进行分配,都会产生什么影响?”
@iammilind:好吧,如果没有影响,那么我甚至不需要CreateObject函数…@Zach:你可以拥有一个不带键的重载版本的CreateObject
,对于可公开创建的类。在非C++bleedingEdge中,您可以使用类似效果的宏,尽管您的同事可能会将您钉死。@Chris:具体用于哪一部分?如果你的意思是为了创建struc
// ...
static MyPtr<Foo> GetNewInstance()
{
Constructor<Foo> c( arg1, arg2, arg3 );
return CreateObject<Foo>( c );
}
template <typename T, typename Creator>
MyPtr<T> CreateObject( Creator creator )
{
// Do something here first...
return MyPtr<T>(creator());
}
class Foo
{
private:
Foo() {}
static Foo* create() { return new Foo(); }
public:
static MyPtr<Foo> GetNewInstance() {
return CreateObject<Foo>( &Foo:create );
}
// ...
};