I have the following class:
template <typename T=void>
class Foo{
public:
Foo(){};
template <typename = typename std::enable_if_t<!std::is_void<T>::value, std::nullptr_t>>
Foo(const T&){};
};
int main() {
Foo<void> v;
}
v
is created using the first constructor. Therefore, there is no need to create the second constructor for Foo<void>
.
Why does it get created anyways?
The problem is that explicitly creating the second constructor with the type void
bypasses SFINAE, and tries to make a parameter of const void&
. This is obviously not allowed.
How can I prevent the second constructor from being valid if T
is void
?
Why does it get created anyways?
Because in your template constructor
template <typename = typename std::enable_if_t<!std::is_void<T>::value, std::nullptr_t>>
Foo(const T&){};
the value of the test for std::enable_if
( :std::is_void<T>::value
) depends from the template type of the class ( T
).
To SFINAE enable/disable a method of a class (or struct) you have to write a test that depends from a template parameter of the method itself.
A way to circumvent this problem is add a template parameter U
for the method and give it T
as default type. I mean something as
template <typename U = T,
typename = std::enable_if_t<!std::is_void<U>::value, std::nullptr_t>>
Foo(const U&){} // ..... the test depends from U ---^
// ^--- U also here, to avoid the void reference problem
or, maybe better,
template <typename U = T,
std::enable_if_t<!std::is_void<U>::value, std::nullptr_t> = nullptr>
Foo(const U&){}
An alternative to disabling the constructor is to replace const T&
with some unusable type when T
is void:
struct unusable {
unusable() = delete;
unusable(const unusable&) = delete;
~unusable() = delete;
};
template <typename T=void>
class Foo{
using cref = std::conditional_t<std::is_void_v<T>, unusable, std::add_lvalue_reference_t<const T>>;
public:
Foo(){}
Foo(cref){}
};
This is useful const T&
it is used in multiple places so you don't have to use SFINAE everywhere.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.