能否将一个 vector<shared_ptr<T>> 传递给一个 const vector<shared_ptr<const T>>& 参数?

3
假设我们有以下函数:
void doStuff(const std::vector<std::shared_ptr<const Foo>>& fs) { }

有没有一种(安全的)方法将std::vector<std::shared_ptr<Foo>>传递给这个参数?例如:
std::vector<std::shared_ptr<Foo>> foos;
doStuff(foos);

这种隐式转换失败了,但是可以通过强制类型转换来安全地完成吗?(从理论上看,这似乎是安全的,因为doStuff函数将无法修改向量,也无法修改其中的对象。)


我发现将const项目制作为shared_ptr会增加不必要的复杂性。但我认为你不能在没有hack的情况下做到这一点。 - Anon Mail
这绝对是未定义的行为。就内存布局而言,它可能看起来每次都能正常工作,但您不能依赖它。谁知道编译器可能进行什么转换,包括省略任何呈现未定义行为的代码。 - François Andrieux
什么是未定义行为?我的问题中的代码无法编译,所以也许你指的是一些假设的 const_cast - jtbandes
@jtbandes 抱歉,我指的是一个假设的 reinterpret_cast 或 c 式转换。我不明白为什么 const_cast 可以解决这个问题。如果只是一个 const_cast,它可能会被很好地定义。const_cast 无法将 std::vector<const T>& 转换为 std::vector<T>& - François Andrieux
@AnonMail 我明白这样做会增加复杂性,但是在这里省略 const 也会允许被调用者修改底层对象。有没有什么方法可以避免这种情况?我想,如果 shared_ptr 只有 T* operator->();const T* operator->() const;,那么它就可以与 const vector<shared_ptr<T>> 正常工作,但事实并非如此... - jtbandes
@jtbandes,你是在说doStuff是回调到用户代码的吗? - Anon Mail
2个回答

2

The short answer is "No".

Given a class template

template <typename T> struct Foo {};

Foo<int>Foo<const int>是两个不同的类型。这两种类型之间没有隐式转换。

我的建议是将doStuff作为函数模板。

template <typename T>
void doStuff(const std::vector<T>& fs) { }

或者

template <typename T>
void doStuff(const std::vector<std::shared_ptr<T>>& fs) { }

如果您没有修改doStuff的选项,为shared_ptr<Foo>复制doStuff中的代码可能是唯一合理的选择。


我知道隐式转换不起作用,但我想知道在这里是否有一些安全使用显式转换的方法。 - jtbandes
作为一种解决方法,值得考虑的是查看std::transform(http://en.cppreference.com/w/cpp/algorithm/transform),并将doSomething更改为逐个获取一个项目并将其转换为正确的类型。 - moka

0
不是的。但你可以改变你的界面,使其更具包容性。你可以这样写:
void doStuff(std::vector<std::shared_ptr<Foo const>> const& fs) { }

但是你真正想要的只是一些连续的 std::shared_ptr<const Foo> 范围,对吧?所以让我们将其更改为:

void doStuff(gsl::span<std::shared_ptr<Foo const>> fs) { }

但是实际上,我们需要共享指针本身指向const吗?还是它们只需要是const就足够了?
void doStuff(gsl::span<std::shared_ptr<Foo> const> fs) { }

现在我们有一个可以使用 std::vector<shared_ptr<Foo>> 调用的接口。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接