模板函数具有调用方的上下文?
Template function having its caller's context?
考虑以下代码片段:
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;
}
不诉诸宏CreateObject(我喜欢MyPtr<type> obj = CreateObject<type>(params)
的语法),是否有一种方法使函数CreateObject与调用函数共享相同的上下文,从而能够访问私有Foo c'tor?"朋友"不是我要找的,因为这意味着任何人调用CreateObject都可以访问私有Foo c'tor,这不是我想要的。重载new操作符也不能工作,因为必须返回一个MyPtr而不仅仅是T*(通过将T*赋值给MyPtr,将一个类型赋给其他地方需要的对象)。
我想我要找的是宏和模板函数之间的东西(模板函数的语法,但像宏一样完全扩展)。在这种特殊情况下,这个特性将非常有用。
可以使用passkey模式:
template<class T, class PassKey>
MyPtr<T> CreateObject(PassKey const& key)
{
return new T(key);
}
class FooKey{
private:
FooKey(){} // private ctor
FooKey(const FooKey&); // undefined private copy ctor
friend class Foo;
};
class Foo{
public:
// public ctor
Foo(FooKey const&){}
static MyPtr<Foo> GetNewInstance()
{
return CreateObject<Foo>(FooKey());
}
};
以Ideone为例。
在c++ 0x中,这比每次创建一个新的Key
结构体要容易得多,因为现在允许模板参数为friend
s:
template<class T>
struct PassKey{
private:
PassKey(){}
PassKey(const PassKey<T>&);
friend T;
};
这基本上与尝试将make_shared
与私有构造函数一起使用相同。
允许这样做的唯一方法是使用friend
。恐怕你已经被这个案子困住了。
我不确定你想达到什么目的。把问题简化到这里已经忽略了整个问题的实际需要。所以我就假设你知道你在做什么,你真的需要这个(我建议你重新考虑你是否需要它,因为我看不出有什么意义…)
无论如何,您可以通过向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 );
}
// ...
};
然而,实际的问题是首先在这里做一些事情实际上做了什么,迫使您进入这个复杂的创建模式。它必须在创建新对象之前执行,这一事实似乎表明存在代码中未显示的隐藏依赖关系,这通常以维护噩梦告终,在那里有人重新排序一些代码,或者添加一个新的构造函数,一切似乎都崩溃了。重新审视您的设计,并考虑是否可以简化或明确这些依赖关系。
因为你是new
在最后的对象,它真的不涉及到你的CreateObject
函数。所以将函数原型改为:
template <typename T>
MyPtr<T> CreateObject(T* const p)
{
//...
return MyPtr<T>(p);
}
用法:
static MyPtr<Foo> GetNewInstance()
{
return CreateObject(new Foo());
}
是否有办法使函数CreateObject与调用函数
共享相同的上下文?
是的,传递你需要的上下文作为参数(作为模板的参数,或者作为函数的参数)。
在实践中,将new T
调用移动到一个单独的函数(或结构模板,正如我在这里选择的那样),如下所示:
// 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>()();
}
};
如果你想处理不同的构造函数签名(读:如果不是所有类型T
都有相同的构造函数签名),你也可以选择不将构造函数作为模板传递给CreateObject
结构体,而是使用函数参数。这样,你就可以像这样"加载"一个Constructor
:
// ...
static MyPtr<Foo> GetNewInstance()
{
Constructor<Foo> c( arg1, arg2, arg3 );
return CreateObject<Foo>( c );
}
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 我的一些 D3D11 对象在调用某些设备上下文函数时将自身作为 ComPtrs 为空
- E/libEGL:调用没有当前上下文的 OpenGL ES API (每个线程记录一次) - Android/SDL
- 在调用运算符重载时识别调用上下文/用法C++
- 如何将有关最顶层调用/上下文的信息添加到异常
- 如何修复C#应用程序中调用C++DLL函数时的上下文加载错误
- 删除程序的调用上下文
- 为什么从 DLL 调用 boost::wave::上下文构造函数时会死锁
- 使用后期绑定从非私有上下文调用私有方法
- 提升 asio ssl:如果私钥传递上下文::use_private_key,则不调用密码回调
- C++类方法,可以使用虚拟调度或类似于没有对象上下文的静态函数来调用
- QTableWidget-QMenu上下文菜单-AddAction插槽不调用函数
- 根据调用方/上下文专门化函数的行为
- 从QQuickWidget上下文调用QML方法
- MFC:从不同的类调用上下文菜单单击的函数,而不是让它调用其默认函数
- 模板函数具有调用方的上下文?
- std::condition_variable::notify_one()在没有上下文切换的情况下调用了多次