![](/img/trans.png)
[英]make template class with std::vector<T> non-copyable when T is non-copyable
[英]Template type deduction with a non-copyable class
假設我有一個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與任何具有鎖定/解鎖方法的東西一起使用,而無需借助虛擬功能。
目前,它很簡單,使用如下:
autolocker<some_lock_t> lock(&my_lock); // my_lock is of type "some_lock_t"
但這樣做是違法的:
autolocker lock(&my_lock); // this would be ideal
反正是否有模板類型演繹與此相關(保持在我的autolocker是不可復制的)。 或者只是指定類型最簡單?
是的,你可以使用范圍保護技術
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 很好地優化了這一點 。
遺憾的是,這意味着您必須使您的儲物櫃對象可以復制,因為您需要從制造商函數返回它。 但舊對象不會嘗試解鎖兩次,因為它的指針在被復制時設置為0,所以它是安全的。
顯然,你無法將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(); }
};
我實際上沒有嘗試過,語法可能是錯誤的(我不知道如何獲取特定函數模板實例的地址),但我認為原則上這應該是可行的。 也許有人出現並修復我錯了。
我比范圍守衛更喜歡這個,由於某種原因,我從來沒有真正喜歡過。
autolocker
是一個類模板,而不是一個類。 你的“這將是理想的”是在C ++中展示一些沒有意義的東西。
我認為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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.