Reputation: 823
I'm trying to implement a conditional pointer dereferencing function. The basic idea is as follows:
return is_pointer(arg) ? *arg : arg
In order to limit the number of necessary specialization, I'm attempting to use rvalue references for the case where arg
is not a pointer. Here is my current implementation (the std::cout
are there solely for debugging purpose):
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T&& t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return t;
}
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == true, typename std::remove_pointer< T >::type& >::type deref(T t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return *t;
}
Now, I get a rather strange behavior under GCC 4.6. The first overload is used for both the non-pointer types and the pointer types. Obviously, when using a pointer type, it conflicts with the second overload. If I comment out the second one and call the following using the first one...
int q;
int *p = &q;
deref(p);
... the corresponding console output is:
0
Pi
How is it possible that a non-pointer type (according to std::is_pointer
) is also a pointer type (according to typeid
) in the same context? The conflict arises between both overloads due to std::is_pointer
wrongly reporting p
as a non-pointer type. Also, when I replace the r-value reference with a standard reference in the first overload:
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T& t)
It doesn't conflict with the second overload anymore... I simply don't get what's going on. By the way, using the second overload yields (as would be expected):
1
Pi
Thanks for your help.
Upvotes: 1
Views: 721
Reputation: 41331
As far as I understand
template <T>
void foo(T&&)
means that if T
is a lvalue, it will be deduced as a reference (T = int*&
in your case) and after reference collapsing of int*&&&
yields a regular lvalue reference int*&
. If it wasn't like that, this syntax would capture anything as a rvalue reference. Whereas the point is to bind lvalues to lvalue references and rvalues to rvalue references.
And is_pointer<int*&>
is not true. Hence you might try applying remove_reference<T>
.
Upvotes: 3
Reputation: 218700
In your first overload T is being deduced as int*&. Try in your first overload to use remove_reference<T>::type
in your enable_if-testing and output.
Upvotes: 2