我正在学习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>
的下一步。
非常感谢。
答案 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);
}
}