Wrapper to create std :: unique_ptr using simple functions

I tried to implement a std::unique_ptrfactory that I could use like this:

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

Ie, pass the deleter function as a template argument.

My best attempt in C ++ 11 was:

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);
}

In C ++ 14 it is much cleaner:

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);
}

But for both solutions, you will need to pass the type &fcloseto fcloseas a template argument:

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

Is it possible to get rid of a template argument decltype(&fclose)in C ++ 11? How about in C ++ 14?

EDIT: RAII ++: RAII ++, - std::unique_ptr . RAII std::unique_ptr , , , C.

+4
4

decltype(&fclose) ++ 11? ++ 14?

, ++ 17 . , , , - . .

, , . , , &fclose . - - :

auto my_fclose_lam = [](std::FILE* f) { std::fclose(f); }
void my_fclose_fun(std::FILE* f) { std::fclose(f); }

, ++ 14 :

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

++ 17 ( ) template auto:

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);
}

my_make_unique<my_fclose_fun>(fopen(...));

++ 20, , :

my_make_unique<[](std::FILE* f){ std::fclose(f); }>(fopen(...));

:

:

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

, , , .


++ 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);
}

+4

: deleter .

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);     
}
+4

:

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% .

+2

std::unique_ptr FILE* :

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);
0

Source: https://habr.com/ru/post/1674696/


All Articles