Home > Back-end >  Overload std::unique_ptr deleter method using std::enable_if
Overload std::unique_ptr deleter method using std::enable_if

Time:09-17

I am trying to write a deleter for my std::unique_ptr, and I would like to overload the method for deletion. Here is what I tried, but the compiler complains about the use of std::enable_if_t. Code is compiled using -std=c 20 flag.

template <class T>
class custom_deleter
{
public:
    template <class U, std::enable_if_t<std::is_array_v<T>, bool> = true>
    void operator()(U* ptr) { std::cout << "array"; }

    template <class U, std::enable_if_t<!std::is_array_v<T>, bool> = true>
    void operator()(U* ptr) { std::cout << "non-array"; }
};

Here's the compiler error:

main.cpp:17:10: error: no type named 'type' in 'struct std::enable_if<false, bool>'
   17 |     void operator()(U* ptr) { std::cout << "non-array"; }
      |          ^~~~~~~~

I don't understand the issue. At first, I thought I was missing an included or compile flag for std::enable_if_t to be available, but its not the problem here. Any help appreciated.

CodePudding user response:

SFINAE required a template parameter of the function to be depended on. That means the std::enable_if_t can only be applied for the U not for the class template T. Therefore, you need to include the template parameter T in your operator()s somehow (like class U = T) or just if constexpr the operator() as you are anyway have acces to :

template <class T>
class custom_deleter
{
public:
    template <class U = T>
    void operator()(U* ptr)
    {         
        if constexpr(std::is_array_v<U>)  std::cout << "array"; 
        else if constexpr(!std::is_array_v<U>)  std::cout << "non-array";
    }
};

int main()
{
    custom_deleter<int[2]> arrDel;
    custom_deleter<std::string> strDel;
    return 0;
}

CodePudding user response:

SFINAE kicks in when choosing what function to call, but your condition depends on T only not on U. Actually not sure if this is the right explanation, sfinae makes me dizzy :P. As you are using C 20 I would suggest constexpr if rather than SFINAE. Anyhow, this compiles:

#include <iostream>
#include <type_traits>


template <class T>
class custom_deleter
{
public:
    template <class U,class W=T, std::enable_if_t<!std::is_array_v<W>, bool> = true>
    void operator()(U* ptr) { std::cout << "non-array"; }

    template <class U,class W=T, std::enable_if_t<std::is_array_v<W>, bool> = true>
    void operator()(U* ptr) { std::cout << "array"; }

};


int main(){
    custom_deleter<int> p{};
    p("asd");
}

On a second thought.. why is there U and T ? Don't you want a custom_deleter<T> to delete Ts? I suppose you actually want this:

template <class T>
class custom_deleter
{
public:
    template <class U=T, std::enable_if_t<!std::is_array_v<U>, bool> = true>
    void operator()(U* ptr) { std::cout << "non-array"; }

    template <class U=T, std::enable_if_t<std::is_array_v<U>, bool> = true>
    void operator()(U* ptr) { std::cout << "array"; }

};


int main(){
    custom_deleter<int> p{};
}
  • Related