假设我有一个autolocker类,它看起来像这样:
template <T>
class autolocker {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
~autolocker() {
lock->unlock();
}
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
T *lock;
};
显然,我们的目标是能够将这个自动锁定器与任何具有锁定/解锁方法的东西一起使用,而不需要使用虚拟功能。
目前,这样使用起来非常简单:
autolocker<some_lock_t> lock(&my_lock); // my_lock is of type "some_lock_t"
但这样做是违法的:
autolocker lock(&my_lock); // this would be ideal
无论如何都要获得模板类型演绎以便与此相配(保持在我的autolocker中是不可复制的)。或者只是指定类型最简单吗?
答案 0 :(得分:5)
是的,你可以使用范围保护技术
struct autolocker_base {
autolocker_base() { }
protected:
// ensure users can't copy-as it
autolocker_base(autolocker_base const&)
{ }
autolocker_base &operator=(autolocker_base const&)
{ return *this; }
};
template <T>
class autolocker : public autolocker_base {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
autolocker(const autolocker& o)
:autolocker_base(o), lock(o.lock)
{ o.lock = 0; }
~autolocker() {
if(lock)
lock->unlock();
}
private:
autolocker& operator=(const autolocker&);
private:
mutable T *lock;
};
然后编写一个创建自动锁定器的函数
template<typename T>
autolocker<T> makelocker(T *l) {
return autolocker<T>(l);
}
typedef autolocker_base const& autolocker_t;
然后您可以这样写:
autolocker_t lock = makelocker(&my_lock);
一旦const引用超出范围,就会调用析构函数。它不需要是虚拟的。至少是GCC optimizes this quite well。
可悲的是,这意味着您必须使您的储物柜对象可以复制,因为您需要从制造商函数返回它。但旧对象不会尝试解锁两次,因为它的指针在被复制时设置为0,所以它是安全的。
答案 1 :(得分:2)
显然,你无法将autolocker
作为模板,因为你想将它作为一种类型使用,并且必须实例化模板才能获得类型。
但是类型擦除可能会用来做你想要的。您将类模板及其构造函数转换为成员模板。但是你必须动态分配一个内部实现对象 更好的是,存储指向执行解锁的函数的指针,并让该函数成为模板化构造函数选择的模板的实例。这些方面的东西:
// Comeau compiles this, but I haven't tested it.
class autolocker {
public:
template< typename T >
autolocker(T *l) : lock_(l), unlock_(&unlock<T>) { l->lock(); }
~autolocker() { unlock_(lock_); }
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
typedef void (*unlocker_func_)(void*);
void *lock_;
unlocker_func_ unlock_;
template <typename T>
static void unlock(void* lock) { ((T*)lock)->unlock(); }
};
我实际上没有试过这个,语法可能是错的(我不知道如何获取特定函数模板实例的地址),但我认为原则上这应该是可行的。也许有人出现并修复我错了。
我比护卫队更喜欢这个,因为某种原因,我从来没有真正喜欢过。
答案 2 :(得分:1)
autolocker
是一个类模板,而不是一个类。你的“这将是理想的”在C ++中显示出一些没有用的东西。
答案 3 :(得分:1)
我认为jwismar是正确的,你想要的东西是不可能的C ++。但是,使用C ++ 0x可以使用类似的(非直接模拟)构造,使用几个新功能(rvalues / moving和auto variable类型):
#include <iostream>
template <typename T>
class autolocker_impl
{
public:
autolocker_impl(T *l) : lock(l) {
lock->lock();
}
autolocker_impl (autolocker_impl&& that)
: lock (that.lock)
{
that.lock = 0;
}
~autolocker_impl() {
if (lock)
lock->unlock();
}
private:
autolocker_impl(const autolocker_impl&);
autolocker_impl& operator=(const autolocker_impl&);
private:
T *lock;
};
template <typename T>
autolocker_impl <T>
autolocker (T* lock)
{
return autolocker_impl <T> (lock);
}
struct lock_type
{
void lock ()
{ std::cout << "locked\n"; }
void unlock ()
{ std::cout << "unlocked\n"; }
};
int
main ()
{
lock_type l;
auto x = autolocker (&l);
}