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

问题描述:

我正在学习C++。 我想让编译器将nullptr推断为shared_ptr。 请仔细阅读下面的代码,如何让编译器推导出一种nullptr类型?

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

GetSharedPtrClassBnullptr不能推导出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>

非常感谢。

+0

@Someprogrammerdude:谢谢你的评论。在我的实际代码中,类A可以是C,因为元编程。所以我想让推导出shared_ptr类型的。 – mora

+1

这是更好地展示实际的问题,因为现在每个人都需要猜测哪种方法最适合([XY问题(https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)) ...另请参阅如何提出一个很好的问题:MCVE(https://stackoverflow.com/help/mcve) –

使用条件操作员从nullptr为 “任何” 强制转换:

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

转换,从一个操作数到另一个条件运算符是明确的(见[expr.con d]),这里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 {}; 
    } 
} 
+0

这是最实用的建议,我觉得 – sehe

+1

@sehe我想我找到了更好的,请参阅编辑;) – Holt

+0

@Holt:感谢你回答。但它给我一个错误“创建初始化列表”。 – mora

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

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

:谢谢你的评论吧。在我的实际代码中,类A可以是C,因为元编程。所以我想让推导出shared_ptr类型的。 – mora

+0

@mora - 对不起,是AFK。霍尔特的回答正是你应该做的增加扣除。我建议你接受这个答案。 – StoryTeller

+0

这是我更少的解释。你的答案是我的一个解决方案。谢谢你再次回答。 – mora

您可以使用static_cast这样的:

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

:谢谢你的评论。在我的实际代码中,类A可以是C,因为元编程。所以我想让推导出shared_ptr类型的。 – mora

+0

好的错过了...... –

我会假设你的代码在一个通用的背景下实际使用。如果你的代码不使用模板,不要使用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;

+0

谢谢你告诉我两种使用decltype的方法。 – mora