2015-10-27 60 views
1

在C++ 11具有保護類,它負責調用的範圍出口的一些成員函數:專營成員指針模板參數分辨率

template <class T, void (T::*op)()> 
struct Guard 
{ 
    Guard(T*g): 
     _g(g){} 
    ~Guard() 
    { 
     (_g->*op)(); 
    } 
    T*_g; 
}; 

用法很簡單:

typedef Guard<Foo, &Foo::bar> FooGuard; 
... 
FooGuard g(&foo); 

我的問題起源於現有的shared_ptr<Foo>。如何創建專業化,保持的T*shared_ptr<T>代替

我已經嘗試過:

template <class T, void (T::*op)()> 
struct Guard<std::shared_ptr<T>, op> 
{ 
    Guard(std::shared_ptr<T>& g): 
     _g(g){} 
    ~Guard() 
    { 
     ((*_g).*op)(); 
    } 

    std::shared_ptr<T> _g; 
}; 

但是在編譯期間G<std::shared_ptr<Foo>, &Foo::bar> g2(foo);有可預見的了:

錯誤C2440: '專業化':不能從'重載函數'轉換爲'void(__thiscall std :: shared_ptr :: *)(void)'

+0

'_g-> OP();'是否行得通呢? –

+0

@DavidHaim在哪裏? – Dewfy

+0

在析構函數中 –

回答

1

作爲@PiotrSkotnicki已經指出,你的專業化是無效的。 您可以使用類似以下,但接口不看,那該多好:

template <class T, class U, void (U::*op)()> 
struct Guard 
{ 
    Guard(T*g): 
     _g(g){} 
    ~Guard() 
    { 
     std::cout << "normal guard" << std::endl; 
     (_g->*op)(); 
    } 
    T*_g; 
}; 


template <class T, class U, void (U::*op)()> 
struct Guard<std::shared_ptr<T>, U, op> 
{ 
    Guard(std::shared_ptr<T>& g): 
     _g(g){} 
    ~Guard() 
    { 
     std::cout << "shared_ptr guard" << std::endl; 
     ((*_g).*op)(); 
    } 

    std::shared_ptr<T> _g; 
}; 

演示:

struct Foo 
{ 
    void bar() 
    { 
     std::cout << "Foo::bar()" << std::endl; 
    } 
}; 

int main() 
{ 
    Foo foo; 
    { 
     typedef Guard<Foo, Foo, &Foo::bar> FooGuard; 
     FooGuard g(&foo); 
    } 

    std::shared_ptr<Foo> foo_ptr = std::make_shared<Foo>(); 
    { 
     typedef Guard<std::shared_ptr<Foo>, Foo, &Foo::bar> FooGuard; 
     FooGuard g(foo_ptr); 
    } 

    return 0; 
} 

輸出:

normal guard 
Foo::bar() 
shared_ptr guard 
Foo::bar() 

live example

1

我會建議使用lambda函數,而不是和捕獲的值:

#include <functional> 
#include <memory> 

struct Guard 
{ 
    typedef std::function<void()> func_type; 

    Guard(const func_type& f): func(f) {} 
    ~Guard() { if (func) func(); } 

    func_type func; 
}; 

struct Foo 
{ 
    void bar() {} 
}; 

int main() 
{ 
    auto foo_ptr = std::make_shared<Foo>(); 
    Guard g([foo_ptr](){ foo_ptr->bar(); }); // note the capture by value 
} 

請注意,您可以自由通過參考捕捉過,如果你想守護的堆棧例如在分配的一個實例。

+0

好吧,解決方案是敏捷的,但我需要關心每個'Guard'創建的清理操作,而不是定義一次 – Dewfy

+0

@Dewfy不知道我理解你的評論;如何使用指針和部分模板專業化比這更清潔? – Sheljohn

1

如果你真的要堅持醜陋的方式,我會建議使用刪除器:

#include <string> 
#include <memory> 
#include <cstdio> 

template < class T, void (T::*op)() > 
struct Guard 
{ 
    Guard(T *p): ptr(p, [](T*){}) {} 
    Guard(const std::shared_ptr<T>& p): ptr(p) {} 

    ~Guard() { if (ptr) ((*ptr).*op)(); } 

    std::shared_ptr<T> ptr; 
}; 

struct Foo 
{ 
    Foo(const char* n): name(n) {} 
    void bar() { printf("Hello from %s\n",name.c_str()); } 

    std::string name; 
}; 

int main() 
{ 
    auto foo1 = Foo("Bob"); 
    auto foo2 = std::make_shared<Foo>("Alice"); 

    Guard<Foo,&Foo::bar> g1(&foo1), g2(foo2); 
} 
+1

其實我想用專業化來完成這個,所以最終用戶在很多情況下都有透明的守衛對象聲明。這就是爲什麼我要接受@ m.s。最接近我的想法。但無論如何+1,因爲它工作正常 – Dewfy