Reputation: 367
I have encountered the following technique that allows the construction of a wrapper object around T
, but from objects of type U
, if T
is constructible from U
:
template< typename T >
struct S {
template< typename U,
typename = std::enable_if_t<
std::is_constructible< T, U >::value > >
explicit S (U&& arg) : value (arg)
{ }
...
};
IIUC, the type U
used in the is_constructible
test can be different from the cv-qualified type of arg
.
Is it possible that the SFINAE test could fail although the expression value(arg)
is valid?
Upvotes: 4
Views: 132
Reputation: 50540
Is it possible that the SFINAE test could fail although the expression value(arg) is valid?
The way you wrote S
: yes, it's possible.
It follows a minimal, (not) working example:
#include<type_traits>
template< typename T >
struct S {
template< typename U
, typename = std::enable_if_t<std::is_constructible< T, U >::value >
> explicit S (U&& arg) : value{arg} {}
T value;
};
struct A {};
struct B {
B(A &) {}
};
int main() {
S<B> s(A{});
}
The code above doesn't compile, but it does compile if you comment out the following line:
, typename = std::enable_if_t<std::is_constructible< T, U >::value >
The problem is that you are not forwarding the constructor parameter. Instead, you are using an lvalue reference to a variable of type rvalue reference to A
(that is arg
) as an argument for value
.
B
is not constructible from an rvalue reference to A
and the sfinae expression fails (correctly), but you are not actually using such a reference to construct the parameter, so removing the sfinae expression it works.
In fact, B
is constructible from an lvalue reference to A
, that is what you are using when you write value{arg}
.
You should rather write S
as it follows:
#include<utility>
// ...
template< typename T >
struct S {
template< typename U
, typename = std::enable_if_t<std::is_constructible< T, U >::value >
> explicit S (U&& arg) : value (std::forward<U>(arg)) { }
T value;
};
Note the use of std::forward
to actually forward the parameters with the right types.
This at least solves the above mentioned issue and it should give you the guarantees you were looking for.
Upvotes: 4