1

我想实现一个条件指针解引用函数。其基本思路是:C++函数模板专业化的行为与右值引用

return is_pointer(arg) ? *arg : arg 

为了限制需要专业化的数量,我试图用右值引用了其中arg不是指针的情况。这是我目前的实现(std::cout在那里仅用于调试目的):

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; 
} 

现在,我得到GCC 4.6下一个相当奇怪的行为。第一个重载用于非指针类型和指针类型。显然,使用指针类型时,它与第二次重载冲突。如果我注释掉第二个和呼叫使用的第一个下面...

int q; 
int *p = &q; 
deref(p); 

...对应的控制台输出为:

0 
Pi 

这怎么可能是一个非指针类型(根据std::is_pointer)也是指针类型(根据typeid)在相同的上下文中?由于std::is_pointer错误地将p错误地报告为非指针类型,所以两个过载之间出现冲突。此外,当我更换的第一个重载标准参考R值参考:

inline typename std::enable_if< std::is_pointer<T>::value == false, T >::type deref(T& t) 

它不与第二过载了冲突......我只是不明白这是怎么回事。顺便说一句,使用第二次超载收益(如预期):

1 
Pi 

感谢您的帮助。

回答

3

据我了解

template <T> 
void foo(T&&) 

意味着如果T是一个左值,它会被推断为(你的情况T = int*&)的参考和借鉴倒塌的int*&&&后产生有规律的左值参考int*&。如果不是这样的话,这个语法会捕获任何东西作为右值引用。而重点是将左值与左值引用和右值绑定为左值引用。

is_pointer<int*&>不正确。因此你可以尝试申请remove_reference<T>

+0

感谢您的深入解释。当我在enable_if条件中使用remove_reference时,它的确编译。我不完全明白你的意思: – pmjobin 2011-02-11 21:13:31

2

在第一次重载时,T被推导为int * &。尝试在第一次重载时在enable_if-testing和output中使用remove_reference<T>::type