C ++ - 使用右值引用的函数模板特化的行为

时间:2011-02-11 20:36:44

标签: c++ c++11 template-specialization rvalue-reference enable-if

我正在尝试实现条件指针解除引用功能。基本思路如下:

return is_pointer(arg) ? *arg : arg

为了限制必要的专业化数量,我试图在arg不是指针的情况下使用rvalue引用。这是我当前的实现(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

感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

据我了解

template <T>
void foo(T&&)

表示如果T是左值,则会将其推断为参考(在您的情况下为T = int*&),并且在参考折叠int*&&&后会产生常规左值参考{{1 }}。如果不是这样,则此语法将捕获任何内容作为右值引用。而重点是将左值与左值引用绑定,将右值与左值引用绑定。

并且int*&不是真的。因此,您可以尝试应用is_pointer<int*&>

答案 1 :(得分:2)

在你的第一次重载中,T被推断为int *&amp ;.尝试第一次重载,在enable_if-testing和output中使用remove_reference<T>::type