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 c 20:
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{};
}
