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 T
s? 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{};
}