std :: is_pointer检查通用引用

时间:2017-10-20 14:01:06

标签: c++ c++14

我编写了一个函数来检查给定变量是否为指针类型:

template<typename T>
void CheckIfPointer(T&& value)
{
    static_assert(std::is_pointer<typename std::remove_reference<T>::type>::value, "T must be of pointer type");
}

我在这里使用通用引用,因为我不想限制可以传入的值类别。但是,我注意到,在这个示例中:

char const* mystr = "Hello World";
CheckIfPointer(mystr);

类型T实际上是const char *&(根据clang)。 remove_reference这里适当的解决方案也是如此吗?或者是否有更简洁的方法来检查实际类型,而不会引用阻碍?

请注意,我只支持C ++ 14。

1 个答案:

答案 0 :(得分:3)

  

类型T实际上是const char *&(根据clang)。

模板参数推断中有一条特殊规则,用于允许完美转发。在模板参数推导的上下文中,T&&不是右值引用,而是转发引用

如果将左值传递给采用转发参考的函数模板,则类型参数将推导为T&而不是T。这样就可以进行引用折叠T& &&变为T&

来自cppreference

  

如果P是对cv非限定模板参数(所谓的转发引用)的右值引用,并且相应的函数调用参数是左值,则使用对A的类型左值引用代替A进行推导(注意:这是std :: forward动作的基础注意:在类模板参数推导中,类模板的模板参数永远不是转发引用(因为C ++ 17))

template<class T>
int f(T&&);       // P is an rvalue reference to cv-unqualified T (forwarding reference)
template<class T>
int g(const T&&); // P is an rvalue reference to cv-qualified T (not special)

int main()
{
    int i;
    int n1 = f(i); // argument is lvalue: calls f<int&>(int&) (special case)
    int n2 = f(0); // argument is not lvalue: calls f<int>(int&&)

//  int n3 = g(i); // error: deduces to g<int>(const int&&), which
                   // cannot bind an rvalue reference to an lvalue
}
  

remove_reference也是适当的解决方案吗?或者是否有更简洁的方法来检查实际类型,而不会引用阻碍?

是的,remove_reference在这里是合适的。您可能希望使用std::remove_reference_t来避免使用明确的typename::type

另外,为什么要通过转发参考传递指针?您确定不想通过左值参考传递吗?

考虑改为使用const T&

template<typename T>
void CheckIfPointer(const T& value)
{
    static_assert(std::is_pointer<T>::value, "T must be of pointer type");
}