g ++ - 如何禁用从0到指针类型的隐式转换?

时间:2014-08-23 14:11:56

标签: c++ g++

具体来说,我希望以下代码失败:

void a(void*){}
int main(){
    a(0); // FAIL
    a(NULL); // FAIL
    a(nullptr); // success
}

我想要编译以下代码:

void a(int){}
void a(void*){}
int main(){
    a(0); // calls first a
    a(NULL); // calls first a; that's why I have -Werror
    a(nullptr); // calls second a
}

以下代码目前无法编译,但应根据我的规则:

void a(std::size_t){}
void a(void*){}
int main(){
    a(0); // two candidates
}

任何想法如何使g ++表现得那样?

5 个答案:

答案 0 :(得分:5)

您可以使用-Wzero-as-null-pointer-constant进行编译,以便在使用0或NULL而非nullptr时收到警告。为了将其提升为错误,我相信使用-Werror=zero-as-null-pointer-constant会有效。

不幸的是,这只是一个警告,无法更改重载解析规则。我还认为必须将NULL定义为0而不是nullptr以便警告才能捕获它,但至少从GCC 4.9开始,std::is_null_pointer<decltype(NULL)>::value is false并且GCC发出警告使用NULL时。

答案 1 :(得分:1)

鉴于NULL0nullptr相同,我认为您不能强迫C ++编译器按照您描述的方式运行。我可以想象使用clang的AST接口来完全按照你描述的方式检测案例。我希望典型的C ++代码会包含0和/或NULL的一些有意使用,以表示适当的指针和/或整数。

答案 2 :(得分:0)

这可能不完美,但是如果你想要使用int和指针进行重载,你可以使用这样的辅助类:

#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;

template<typename T = void> class ptr {
    T* it;
public:
    ptr(T* it = nullptr): it(it) {}
    ptr(const ptr<T>&) = default;
    ptr& operator = (const ptr<T>&) = default;
    operator T* () { return it; }
    T& operator * () { return *it; }
    T* operator -> () { return it; }
    ptr& operator += (int x) { it += x; return *this; }
    ptr& operator -= (int x) { it -= x; return *this; }
    ptr& operator ++ () { ++it; return *this; }
//  etc...
public:
    template<typename P>
      ptr(P* it): it(it) {}
    template<typename P>
      ptr(ptr<P> it): it((T*)it) {}
};
template<> class ptr<void> {
    void* it;
public:
    ptr(void* it = nullptr): it(it) {}
    ptr(const ptr<void>&) = default;
    ptr& operator = (const ptr<void>&) = default;
    operator void* () { return it; }
public:
    template<typename P>
      ptr(P* it): it(it) {}
    template<typename P>
      ptr(ptr<P> it): it((void*)it) {}
};

void a(std::size_t x) {
    cout << "first: " << x << endl; }
void a(ptr<const int> p) {
    cout << "second: " << (p ? *p : -1) << endl; }
void a(ptr<int> p, ptr<> q) {
    cout << "third: " << (p ? *p : -1) << ", "
        << (q ? "some" : "null") << endl;
    a(p); }
int main(){
    a(0);           // first: 0
    a(NULL);        // first: 0 but warning [-Wconversion-null]
    a(new int(3), nullptr); // third: 3, null + second: 3
}

它没有完成(可能删除那个显式,添加更多运算符,从nullptr_t进行特殊转换等),只是想法。

编辑: 代码,模板构造函数和转换为ptr<const int>测试的变化很少。

答案 3 :(得分:0)

这是第一个问题的相对简单的解决方案(它需要C ++ 11):

struct must_be_void_ptr{
    must_be_void_ptr(void* p) : p(p) {}
    must_be_void_ptr(int) = delete; // Disallow implicit conversion from 0
    void* p;
    operator void*() { return p; }
};

void a(must_be_void_ptr p){
    void* vp = p;
}

int main(){
    a(nullptr);
    a(0);
}

答案 4 :(得分:0)

使用:

gsl::not_null

来自Guideline Support Library。我强烈推荐GSL。它是由许多C ++专家(Bjarne Stroustrup本人和Herb Sutter)创建和支持的。并且C++ Core Guidelines正在积极地集成到编译器警告和静态分析器中。