如何让编译器推导出一种nullptr?

时间:2017-06-12 14:15:18

标签: c++

我正在学习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>的下一步。

非常感谢。

4 个答案:

答案 0 :(得分:8)

使用条件运算符强制从nullptr转换为“无论什么”:

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

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

另一方面,使用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 {};
    }
}

答案 1 :(得分:4)

您可以返回默认构造的shared_ptr。

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

答案 2 :(得分:2)

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

要推断返回类型,所有返回语句必须计算为相同类型的表达式。在您的代码中,您有两个返回语句,有两种不同的类型。一个使用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;

答案 3 :(得分:1)

您可以像这样使用static_cast

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