我怎样才能让编译器推导出一种类型的 nullptr

How can I let compiler to deduce a type of nullptr?

本文关键字:一种 nullptr 类型 编译器      更新时间:2023-10-16

我正在学习c++。我想让编译器推断 nullptr 为shared_ptr。请阅读以下代码,

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.
    }
}

GetSharedPtrClassB中,nullptr不能推导出为std::shared_ptr<A>。错误消息如下,

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

如何让编译器推断出 nullptr 作为std::shared_ptr<A>? 我可以提供一个类型decltype(*(tag->b)),但我想不出下一步来提供一个类型std::shared_ptr<A>

谢谢。

使用条件运算符强制从nullptr转换为"whatever":

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

在条件运算符中从一个操作数到另一个操作数的转换是明确定义的(请参阅 [expr.cond](,此处nullptr转换为类型为 decltype(tag->b->a) 的对象。

另一方面,使用没有尾随返回类型的auto时返回类型推断的规则非常严格 - 每个return语句的推导类型必须相同 ([dcl.spec.auto/9](:

如果具有包含占位符类型的声明返回类型的函数具有多个 return 语句, 为每个 return 语句推导返回类型。如果每次扣除的类型不同, 程序格式不正确。


如果函数不能简化为条件运算符,则可以使用尾随返回类型:

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

改为返回默认构造shared_ptr。

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

我将假设您的代码实际上是在通用上下文中使用的。如果您的代码不使用模板,则不使用 decltype,请直接指定类型。

若要推断返回类型,所有 return 语句的计算结果必须为相同类型的表达式。在您的代码中,您有两个具有两种不同类型的 return 语句。一个有std::shared_ptr<A>,一个有std::nullptr_t

有两种解决方案:在两个 return 语句中使用相同的类型,或显式定义返回类型。

下面介绍如何返回相同的类型:

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){};
}

或者显式定义返回类型:

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 {};
}

顺便说一下,在你的代码中,auto& sharedB = *(tag->b); return sharedB.a;可以减少到return tag->b->a;

你可以

像这样使用static_cast

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