2017-04-12 99 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%的情况下,将工作。

相关问题