How can I let the compiler infer the nullptr type?

I am learning C ++. I would like to let the compiler output nullptr as shared_ptr. Please read the following code,

struct A {};

struct B {
    std::shared_ptr<A> a;
};

struct Tag {
    std::shared_ptr<B> b;
};

auto GetSharedPtrClassB(Tag* tag) {
    if (tag) {
        auto& sharedB = *(tag->b);
        return sharedB.a;
    } else {
        return nullptr;  // Error : compiler cannot deduce type of nullptr.
    }
}

      

B GetSharedPtrClassB

, nullptr

cannot be inferred as std::shared_ptr<A>

. Error messages appear,

error: inconsistent deduction forauto’: ‘std::shared_ptr<A>’ and then ‘std::nullptr_t
      

How can I let the compiler output nullptr like std::shared_ptr<A>

? I can provide a type decltype(*(tag->b))

, but I cannot think of the next step to provide a type std::shared_ptr<A>

.

Many thanks.

+3


source to share


4 answers


Use a conditional statement to force the conversion from nullptr

to all:

auto GetSharedPtrClassB(Tag* tag) {
    return tag ? tag->b->a : nullptr;
}

      


Conversion from one operand to another in the conditional operator is correct (see [expr.cond]), here it is nullptr

converted to an object of type decltype(tag->b->a)

.

On the other hand, the rules for inference of the return type when used auto

without a return return type are very strict - the inferred type must be the same for every operator return

([dcl.spec.auto/9]):



If a function with a declared return type that contains a placeholder type has multiple return statements, the return type is inferred for each return statement. If the inferred type is not the same in every output, the program is ill-formed.


If your function cannot be reduced to a conditional operator, you can use the return type:

auto GetSharedPtrClassB(Tag* tag) -> decltype(tag->b->a) {
    if (tag) {
        auto& sharedB = *(tag->b);
        return sharedB.a;
    } else {
        return {};
    }
}

      

+8


source


You can return the default built shared_ptr instead.



auto GetSharedPtrClassB(Tag* tag) {
    if (tag) {
        auto& sharedB = *(tag->b);
        return sharedB.a;
    } else {
        return std::shared_ptr<A>{};
    }
}

      

+4


source


I am assuming that your code is indeed being used in a general context. If your code doesn't use templates, don't use decltype, specify types directly.

To infer the return type, all return statements must evaluate to an expression of the same type. In your code, you have two return statements with two different types. One s std::shared_ptr<A>

and one s std::nullptr_t

.

There are two solutions: use the same types in both return statements, or explicitly define the return type.

Here's how to return the same type:

auto GetSharedPtrClassB(Tag* tag) {
    if (tag) {
        auto& sharedB = *(tag->b);
        return sharedB.a;
    }

    // empty constructor same as initializing with `nullptr`
    return decltype(tag->b->a){};
}

      

Or specify the return type explicitly:

auto GetSharedPtrClassB(Tag* tag) -> decltype(tag->b->a) {
    if (tag) {
        auto& sharedB = *(tag->b);
        return sharedB.a;
    }

    // empty constructor same as initializing with `nullptr`
    return {};
}

      

By the way, your code auto& sharedB = *(tag->b); return sharedB.a;

can be reduced toreturn tag->b->a;

+2


source


You can use static_cast

like this:

auto GetSharedPtrClassB(Tag* tag) {
    if (tag) {
        auto& sharedB = *(tag->b);
        return sharedB.a;
    } else {
        return static_cast<std::shared_ptr<A> >(nullptr);
    }
}

      

+1


source







All Articles