2017-04-12 98 views
4

我試圖實現一個std::unique_ptr工廠,我可以用這樣的:包裝打造的std ::的unique_ptr與普通函數刪除器

auto fd = my_make_unique<fclose>(fopen("filename", "r")); 

即,通過刪除器功能作爲一個模板參數。

我在C++ 11最好的嘗試是:

template<typename D, D deleter, typename P> 
struct Deleter { 
    void operator()(P* ptr) { 
     deleter(ptr); 
    } 
}; 

template<typename D, D deleter, typename P> 
std::unique_ptr<P, Deleter<D, deleter, P>> my_make_unique(P* ptr) 
{ 
    return std::unique_ptr<P, Deleter<D, deleter, P>>(ptr); 
} 

在C++ 14它是乾淨多了:

template<typename D, D deleter, typename P> 
auto my_make_unique(P* ptr) 
{ 
    struct Deleter { 
     void operator()(P* ptr) { 
      deleter(ptr); 
     } 
    }; 
    return std::unique_ptr<P, Deleter>(ptr); 
} 

但兩者solutuions需要我傳球的&fclose類型之前fclose本身作爲模板參數:

auto fd = my_make_unique<decltype(&fclose), fclose>(fopen("filename", "r")); 

是否有可能擺脫decltype(&fclose) C++ 11中的模板參數?在C++ 14中怎麼樣?

編輯:爲什麼這個問題不是RAII and smart pointers in C++的重複:引用的問題是關於C++中的一般RAII技術,並且其中一個答案可以用於此目的。我已經熟悉RAII模式,以及std::unique_ptr是如何解決的,但我關心的是如何在與C庫交互時遇到的這種常見情況下構建更易於使用的抽象。

+0

'FILE *'只是大家熟悉的一個例子。這對於與充滿'create_ ()'和'destroy_ ()'函數的C庫進行交互最有用。無論如何,'*'和' - >'也可用於普通的'FILE *'指針,並且它在'std :: unique_ptr'中也不會更糟。 – lvella

+0

@Ivella參見http://stackoverflow.com/questions/395123/raii-and-smart-pointers-in-c特別是[this](http://stackoverflow.com/a/395168/8877)回答哪些區別內存和任意資源之間。 –

+0

我不同意這個重複標記,我的問題更具體。 – lvella

回答

5

是否有可能在C++ 11擺脫decltype(&fclose)模板參數的?在C++ 14中怎麼樣?

不,直到C++ 17才能擺脫該參數的類型。模板非類型參數需要一個類型,您無法推斷 - 因爲它必須是模板非類型參數。所以你可以做的最好的是引入一個宏,如:

#define DECL(v) decltype(v), v 
auto fd = my_make_unique<DECL(&fclose)>(fopen("filename", "r")); 

不管你認爲這是一個好主意可能取決於你的同事。


在C++ 17,與template auto,你可以只能夠寫my_make_unique<fclose>,這是偉大的:

template <auto deleter, typename P> 
auto my_make_unique(P* ptr) 
{ 
    struct Deleter { 
     void operator()(P* ptr) { 
      deleter(ptr); 
     } 
    }; 
    return std::unique_ptr<P, Deleter>(ptr); 
} 
5

實用方法:使刪除器成爲運行時參數。

template<typename P, typename D> 
auto my_make_unique(P* ptr, D deleter) 
{ 
    return std::unique_ptr<P, D>(ptr, deleter); 
} 

int main() 
{ 
    auto fd = my_make_unique(fopen("filename", "r"), fclose);  
} 
+0

這就是我目前正在做的。缺點是,除了可能更大的結構之外,返回類型(即typedef)不是默認可構造的。 – lvella

1

的典型方式爲FILE*指針創建std::unique_ptr是:

auto fd = std::unique_ptr<FILE, decltype(fclose)>(fopen(...), fclose); 

你可以包裝在一個宏:

#define my_make_unique(ptr, deleter) \ 
    std::unique_ptr<std::remove_pointer<decltype<ptr>>::type, d>(ptr, deleter) 

,然後用它是這樣的:

auto fd = my_make_unique(fopen(...), fclose); 
1

另一個解決方法是使用的功能完全相同簽名:

template<typename T, int (*P)(T*)> //for `fclose` 
auto my_make_unique(T*) { ... } 

template<typename T, void (*P)(T*)> //for other function signatures 
auto my_make_unique(T*) { ... } 

//etc. 

auto uniq = my_make_unique<File, fclose>(fopen("filename", "r")); 

這不是通用的解決方案,但在95%的情況下,將工作。

相關問題