C++ nullptr

考虑如下代码:

 1 void g(int* i){  }
 2 
 3 int main(){
 4 
 5     g(0); //ok 调用g((int*)0)
 6 
 7     const int x = 0;
 8     g(x); //ok 调用g((int*)0)
 9     
10     int x=0;
11     g(x);  //error. 编译错误,int无法转换int*
12     
13     return 0;
14     
15 }

文字量0的类型,永远是int

编译期int常量0,在遇到转换成指针的场合,会被隐式转换成指针。其它常量不会,1,2,3...都没有这个待遇

0值得这个特殊待遇,遇到变量就会不好使了。例如:第11行,变量x,即使其值为0也没用。这个规则会延续到模板,例如:

template<class PointerType>
void template_call( PointerType x ){
    g(x);
}

void g(int* i){}

int main(){
    template_call(0);
}

这相当于,调用的是:

void template_call( int x )
{
    g(x); //11行一样的失败
}

第一个解决方法是:手动写 template_call( (int*)0); 也没什么缺点,就是需要程序员去查勘g(int*)的参数类型,然后回来把int*拷贝到0的前面。实际上指向任意类型的万能空指针破产了,这是优秀(懒惰)的程序员不能容忍的。因此第二个方案nullptr引入了。

namespace study {

    const class nullptr_t
    {
    public:
        template<class T>
        inline operator T*() const  //隐式转化
        {
            return 0;
        }

        template<class C, class T>  //隐式转化
        inline operator T C::*() const
        {
            return 0;
        }

        void operator&() const = delete;
    } ;
}

template<class PointerType>
void template_call( PointerType a ){
    g(a);
}

void g(int* i){  }

int main(){
    //代替:template_call((int*)0)
    template_call( study::nullptr_t{} );
}

template_call( study::nullptr_t{}) 实例化模板参数PointerType=study::nullptr_t

这样g( study::nullptr_t{} );匹配不了g(int*)啊!!但是我们看到有个nullptr_t到int*的隐式转换:

const class nullptr_t
    {
    public:

        inline operator int*() const  //隐式转化
        {
            return 0;
        }

这样g( study::nullptr_t{}.operator int*() ); 就是 int* tmp=0; g(tmp);的展开结果了。万能空指针又回来了。

f( study::nullptr_t{}); 在标准库std名字空间里是f( std::nullptr_t{} ); 但是还是没有0简洁啊!!

常规思路可能定义个全局对象,例如constexpr std::nullptr_t nullptr; 然后,就简化成f( std::nullptr ); 但是前面那个std::五个字符还是太复杂!!

nullptr就不再是个全局对象了,而被收录成关键字!!就像for ,class一样的。这下好了,std::也省了。就成了f(nullptr)

f( nullptr ) 比 f(0)多敲打6个字符,但是比起f(NULL)只多敲打了3个字符,好像还说得过去。如果把nullptr改成np为关键字,则f(np)是不是更省键盘呢?

 

转载于:https://www.cnblogs.com/thomas76/p/8592904.html

你可能感兴趣的:(C++ nullptr)