Question

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.

Was it helpful?

Solution

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>.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top