How to fix error refactoring decltype inside template

后端 未结 3 1716
萌比男神i
萌比男神i 2021-01-19 07:00

edit Possibly can\'t be done, see Clean implementation of function template taking function pointer although answer 1 there has a C macro work-around https://stacko

相关标签:
3条回答
  • 2021-01-19 07:06

    I think for c++11 it is impossible to achieve what you want.

    template<typename T, typename D>
    class unique_gptr : public std::unique_ptr<T, decltype(&D)> {
        public: unique_gptr(T* t) : std::unique_ptr<T, decltype(&D)>(t, D) { };
    };
    
    using int_gptr = unique_gptr<int, ::free_int>;
    int_gptr ig(new int(2));
    

    Notice that decltype is applied on D, which is declared as a typename. So D is a type. But decltype can't be used on a type.

    Firstly the code tries to get the address of a type (&). Secondly, the argument of decltype is expected to be an expression, but not a type or "the address of a type". To make it easier to understand, we can say that decltype expects its argument to be a “variable”, like the following example.

    int main()
    {
        int i = 10;
        decltype(i) j;
        decltype(int) k; /* Compiler error. */
        decltype(&int) l; /* Compiler error. */
        return 0;
    }
    

    You also want the compiler to replace D with ::free_int. And ::free_int is passed in as a non-type template argument. However D is a type template parameter. A non-type template parameter starts with an actual type (e.g. int, struct a* or a type template name). While a type template parameter starts with typename or class. An easier example for non-type template parameter,

    template<int INIT>
    void func2(void)
    {
        decltype(INIT) j = INIT;
    }
    
    int main()
    {
        func2<10>();
        return 0;
    }
    

    When you pass in a function pointer like ::free_int, you need a non-type template parameter, which must be preceded by a type. And you want the type of the function pointer to be "replaceable". So the type of the function pointer has to be a type template parameter. These make them two template parameters.

    That's the reason you need three template parameters in template<typename T, typename D, D F>, which is the best result you have.

    0 讨论(0)
  • 2021-01-19 07:09

    You can use some macro magic:

    template<class T, class D, D d>
    struct UniqueDeleter : public std::unique_ptr<T, D> {
        UniqueDeleter(T* t) : std::unique_ptr<T, D>(t, d) { };
    };
    
    template<class R, class T>
    T decl_unique_deleter_ptr(R (*d)(T*));
    
    #define DECL_UNIQUE_DELETER1(f) UniqueDeleter<decltype(decl_unique_deleter_ptr(&f)), decltype(&f), &f>
    #define DECL_UNIQUE_DELETER2(T, f) UniqueDeleter<T, decltype(&f), &f>
    #define DECL_UNIQUE_DELETER_GET_MACRO(_1, _2, NAME, ...) NAME
    #define DECL_UNIQUE_DELETER_EXPAND(x) x
    #define decl_unique_deleter(...) DECL_UNIQUE_DELETER_EXPAND(DECL_UNIQUE_DELETER_GET_MACRO( \
        __VA_ARGS__, DECL_UNIQUE_DELETER2, DECL_UNIQUE_DELETER1, _)(__VA_ARGS__))
    

    Now you can use it like such:

    decl_unique_deleter(int, free_int) ig(new int(2));
    

    Or with using and some more magic:

    using int_gptr = decl_unique_deleter(free_int); // If accepted pointer type matches.
    int_gptr ig(new int(2));
    

    I might also recommend an alternative solution:

    auto i = new int(2);
    BOOST_SCOPE_EXIT_ALL(&) { delete i; };
    
    0 讨论(0)
  • 2021-01-19 07:25

    You cannot use decltype with a type as the goal is to obtain the type of a variable. But in decltype(&D), D is a type.

    I would rather pass throught a template function:

    template<typename T, typename D, D F>
    class unique_gptr : public std::unique_ptr<T, D> {
        public: unique_gptr(T* t) : std::unique_ptr<T, D>(t, F) { };
    };
    
    template <typename T, typename D>
    unique_gptr<T, D F> make_unique_gptr(T pointer, D deleter)
    {
        return unique_gptr<T, D, deleter>(pointer);
    }
    
    auto ptr = make_unique(new int(2), ::free_int);
    
    0 讨论(0)
提交回复
热议问题