簡體   English   中英

帶有不可復制類的模板類型推導

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM