我编写了一个函数来检查给定变量是否为指针类型:
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。
答案 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");
}