显式void指针作为函数参数

Explicit void pointer as function parameter

本文关键字:函数 参数 void 指针 显式      更新时间:2023-10-16

我有一个函数:

int foo(void * ptr)
{
   // ...
}

在C++11/14中,我是否可以在语法上(不带编译器警告等(禁止向void *本身以外的指针传递?

例如,现在它可以被称为:

foo(new int(42));

我需要禁用它。

我想还有很多其他方法可以做到这一点

使用模板函数很简单(它也适用于C++98(

template <typename X>
int foo (X * ptr);
int foo (void * ptr)
 { return 1; }
int main()
 {
   int  i;
   void * vp = &i;
   foo(vp);  // OK
   foo(&i);  // linker error
   return 0;
 }

正如frymode所指出的,前面的解决方案给出的是链接器错误,而不是编译器错误,最好是得到编译器错误。

使用delete(来自C++11(,我们可以通过使用以下内容来获得编译器错误:

template <typename X>
int foo (X ptr) = delete;

希望这能有所帮助。

您可以使用迂腐的指针习惯用法。您的代码应该如下所示。它利用了这样一个事实,即在更高的间接级别上没有隐式转换:

[现场]

int foo_impl(void * ptr, void **)
{
   return 0;
}
template <typename T>  
void foo(T* t)  
{  
  foo_impl(t, &t);  
}  
int main()
{
    void* pv;
    foo(pv);
    //foo(new int(2)); // error: error: invalid conversion from 'int**' to 'void**'
}

如果想要精确的类型匹配,可以使用std::enable_If和std::is_same

#include <iostream>
#include <type_traits>
template <typename T,
          typename = typename std::enable_if_t<std::is_same<T, void*>::value>>
int foo(T value)
{
    return 5;
}
int main()
{
    // return foo(new int(42)); // error: no matching function for call to 'foo(int*)'
    return foo((void*)(new int(42)));
}

您可以将函数转换为模板函数,然后使用type_traits:中的static_assertstd::is_void

template<typename T>
int foo(T *ptr) {
    static_assert(std::is_void<T>::value, "!");
   // ....
}

否则,您可以在返回类型上使用std::enable_if_t

template<typename T>
std::enable_if_t<std::is_void<T>::value, int>
foo(T *ptr) {
    // ....
    return 0;
}

等等,其他用户已经提出了其他有趣的解决方案,并给出了他们的答案。

下面是一个最小的工作示例:

#include<type_traits>
template<typename T>
int foo(T *ptr) {
    static_assert(std::is_void<T>::value, "!");
    // ....
    return 0;
}
int main() {
    int i = 42;
    void *p = &i;
    foo(p);
    // foo(&i); // compile error
}

惯用方法是创建一个新类型来表示void*,以避免您所描述的问题。许多优秀C++实践的倡导者建议创建类型,以避免对应该传入的内容产生任何疑问,也避免编译器允许您这样做。

class MyVoid
{
//... implement in a way that makes your life easy to do whatever you are trying to do with your void* stuff
};
int foo(MyVoid ptr)
{
   // ...
}

您不需要C++11来确保编译时出错:

template<class> struct check_void;
template<> struct check_void<void> { typedef void type; };
template<class T> typename check_void<T>::type *foo(T *ptr) { return ptr; }
 
int main()
{
    foo(static_cast<void *>(0));  // success
    foo(static_cast<int *>(0));  // failure
}