显式void指针作为函数参数

vla*_*don 16 c++ void-pointers c++11 c++14

我有一个功能:

int foo(void * ptr)
{
   // ...
}
Run Code Online (Sandbox Code Playgroud)

我可以在C++ 11/14中语法上(不使用编译器警告等)禁用传递除void *自身以外的指针吗?

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

foo(new int(42));
Run Code Online (Sandbox Code Playgroud)

我需要禁用它.

max*_*x66 19

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

使用模板函数很简单(它也适用于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;
 }
Run Code Online (Sandbox Code Playgroud)

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

使用delete(来自C++ 11)我们可以通过使用它来获得编译器错误:

template <typename X>
int foo (X ptr) = delete;
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 这给链接器错误而不是编译器使得查找错误源更加烦人. (3认同)

dew*_*led 10

如果你想要精确的类型匹配,你可以使用std :: enable_ifstd :: 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)));
}
Run Code Online (Sandbox Code Playgroud)

  • 使用`template <typename T,typename ...,typename = typename std :: enable_if_t <std :: is_same <T,void*> :: value >>`而不再可能. (2认同)

mar*_*inj 10

你可以利用迂腐的指针习语.你的代码看起来应该如下.它利用了这样一个事实:在一个间接层的高层没有隐式转换:

[生活]

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**'
}
Run Code Online (Sandbox Code Playgroud)


sky*_*ack 8

您可以将该功能转换为模板1,然后使用a static_assertstd::is_voidfrom type_traits:

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

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

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

等等,其他用户已经提出了其他有趣的解决方案.

这是一个最小的工作示例:

#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
}
Run Code Online (Sandbox Code Playgroud)


kei*_*ith 6

惯用的方法是创建一个新类型来表示,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)
{
   // ...
}
Run Code Online (Sandbox Code Playgroud)