2017-10-20 34 views
3

我有我写了一个函数来检查,如果给定的变量是指针类型:的std :: is_pointer检查与普遍引用

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 *&(根据铛)。那么remove_reference在这里是合适的解决方案吗?或者是否有一种更简洁的方式来检查实际的类型,而没有引用妨碍?

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

+1

如果你想完美转发,你必须处理的引用。此外,你应该使你的函数constexpr, –

+1

有趣的是,void.pointer想检查指针类型:-) – Jarod42

回答

3

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

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

如果左值被传递给服用转发参考函数模板,类型参数推导出作为T&代替T。这允许参考折叠发生:T& &&变成T&

cppreference

如果P是一个rvalue参照CV-不合格模板参数(所谓的转发参考),以及相应的函数调用参数是一个左值,类型左值参照(注意:这是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"); 
} 
+0

它可能或可能不是一个指针,这是我的功能点。我觉得转发引用在这方面比较安全(即不禁止值类型,不强制复制语义等) –

+0

@ void.pointer:...但你是静态断言它是一个指针? –

+0

是的,在我的真实世界的代码中,这实际上是事件系统中“用户数据”的setter方法。这种工作原理的语义是非常传统而不理想的,但是规则是用户数据不能是指针。因此,如果传递一个非指针类型,应该发生编译器错误,以强制用户更正类型。 –