C++ 作为函数参数的显式void指针

C++ 作为函数参数的显式void指针,c++,c++11,c++14,void-pointers,C++,C++11,C++14,Void Pointers,我有一个功能: int foo(void * ptr) { // ... } 在C++11/14中,除了void*本身之外,我是否可以在语法上(不带编译器警告等)禁用传递这些指针 例如,现在可以将其称为: foo(new int(42)); 我需要禁用它。惯用的方法是创建一个新类型来表示void*,以避免您描述的问题。许多优秀的C++实践的倡导者建议创建类型,以避免对应该传入的内容有任何怀疑,也避免编译器允许您。 class MyVoid { //... implement in a

我有一个功能:

int foo(void * ptr)
{
   // ...
}
在C++11/14中,除了
void*
本身之外,我是否可以在语法上(不带编译器警告等)禁用传递这些指针

例如,现在可以将其称为:

foo(new int(42));

我需要禁用它。

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

如果您想要精确的类型匹配,可以使用

#包括
#包括
模板
整数foo(T值)
{
返回5;
}
int main()
{
//返回foo(new int(42));//错误:调用'foo(int*)没有匹配的函数
返回foo((void*)(newint(42));
}

我想还有很多其他的方法

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

希望这有帮助。

您可以利用。您的代码应该如下所示。它利用了这样一个事实,即在较高的间接级别上没有隐式转换:

int foo_impl(void*ptr,void**)
{
返回0;
}
模板
无效foo(T*T)
{  
foo_impl(t&t);
}  
int main()
{
void*pv;
foo(pv);
//foo(新int(2));//错误:错误:从“int**”到“void**”的转换无效
}

您可以将函数转换为模板函数,然后使用
静态断言和
std::is\u void
from
type\u traits

template<typename T>
int foo(T *ptr) {
    static_assert(std::is_void<T>::value, "!");
   // ....
}
等等,其他用户已经提出了其他有趣的解决方案,并给出了他们的答案

下面是一个简单的工作示例:

#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
}
#包括
模板
int foo(T*ptr){
静态断言(std::is\u void::value,“!”;
// ....
返回0;
}
int main(){
int i=42;
void*p=&i;
富(p),;
//foo(&i);//编译错误
}
您不需要C++11来确保编译时错误:
模板结构检查\u void;
模板结构检查_void{typedef void type;};
模板类型名称检查\u void::type*foo(T*ptr){return ptr;}
int main()
{
foo(static_cast(0));//成功
foo(static_cast(0));//失败
}

那么这样做的目的是什么?什么会阻止某人这样做,例如,
void*ptr=reinterpret_cast(新int(42));foo(ptr)?你能详细说明一下这个用例吗,关于你试图解决的实际问题吗?我需要一个“显式的”void参数,就像类内构造函数一样。如果用户明确地重新解释它,这是他的权利。实际问题:想象一下智能指针,类似于
std::unique\u ptr
,它允许
void*
保持,但只允许
void*
传递给构造函数的参数。那么使用模板和@JoachimPileborg怎么样?它可能是一个变体,你能帮助我:模板类的方法如何被禁用,以及基于模板参数禁用吗?@JoachimPileborg:这真是一个愚蠢的论点。这就像说禁止
intptr\u t
也没有意义,因为任何人都可以
重新解释
并将其转换为
无效*
。类型检查是安全功能,而不是安全功能。我喜欢有人为了自己的利益而改变解析规则:)这会导致链接器错误而不是编译器错误,从而使查找错误源变得更加烦人。@frymode-你说得对;谢谢用另一个例子修改了我的答案,这个例子给出了一个编译器错误(但只从C++11开始)。这个防护是一个很弱的防护。看,你可以很容易地用
foo(newint(42))。改用
模板
,这样就不可能了。好把戏!但如果它在某些情况下会干扰优化,我也不会感到惊讶。@Mehrdad
void foo_impl(void*ptr)
;调用有许多选项,例如
static_cast(&t)、foo_impl(t)。编译器应该能够处理这个问题
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**'
}
template<typename T>
int foo(T *ptr) {
    static_assert(std::is_void<T>::value, "!");
   // ....
}
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
}
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
}