gpt4 book ai didi

c++ - 避免将转换运算符中的拷贝复制到基类的子集

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:20:28 24 4
gpt4 key购买 nike

首先:你会大喊“XY problem!”你会是对的,但现在我想看看是否有一个很好的解决方案来解决这个特定的 Y 来判断/最小化它与这个(大)X 的其他 Y 相比的妥协。


考虑以下可变参数模板类,它继承自所有模板参数并为其中的一个子集提供转换运算符:

template <typename... Ts>
struct derived : Ts...
{
template<class... SubTs>
operator const derived<SubTs...>()
{
return { static_cast<SubTs>(*this)... };
}
};

这允许你做这样的事情:

struct A { int a; };
struct B { double b; };
struct C { std::unique_ptr<int> c; };

using ABC = derived<A, B, C>;

int foo(const derived<A, B>& in)
{
return in.a + in.b;
}

int test()
{
ABC abc{ {1}, {3.0}, {std::make_unique<int>(4)}};
return foo(x);
}

虽然转换确实创建了一个临时拷贝以传递给函数。所以您不能执行以下操作,因为 unique_ptr无法复制:

int bar(const derived<A, C>& in)
{
return in.a + *in.c;
}

int test()
{
ABC abc { {1}, {3.0}, {std::make_unique<int>(4)}};
return bar(x);
}

在线代码:https://godbolt.org/z/KBoBDl

是否有解决方案:

  1. 我可以传递一个不可复制的 derived (当然不会放弃所有权)。

  2. 我不必指定 A 中的哪一个 |/B/C in 的给定成员来自(没有in.get<A>().a)。 “使用组合而不是继承”也不是解决方案。换句话说,in.a 的语义(in->a 也可以)应该保留。

  3. foo 的函数参数和 bar在单个可变参数模板列表中拼出它们主体中可用的子类型(不一定必须在 derived 中,尽管我觉得之前的要求强制这样做)。如果我不提 B那么函数不应该访问 B的成员(即使传入的 derived 包含 B )。

改变 foo/bar成为模板函数将是一个挫折,但可以接受。注意 template<class T> int foo(T in) (并删除转换运算符)违反了最后一个要求。另请注意,我使用的是 C++17,因此没有概念。

理想情况下,我会想象函数签名看起来像 int bar(derived_view<A, C> in)但我看不出如何将其与所有要求统一起来。欢迎提供部分想法/解决方案,也许有帮助。

derived 我在可变作曲方面的最佳表现,A/B/C已经都是包装器结构了。这就是为什么不应该有任何进一步的间接访问实际数据的原因。


是的,我知道,“这听起来像是带有额外步骤的普通函数参数!”,但我有很多 foobar需要数十个不同的子集 A/B/C等结构,每一个建筑更多这样的结构。普通函数参数是探索的现状,并不是令人满意的解决方案。

最佳答案

如果我们将 derived_view 限制为“只能用作函数参数”,那么将任何使用过的参数从传递的 derived(或 derived_view) 在其构造函数中并将它们移回到析构函数中:

template <typename... Ts>
struct derived_view : Ts...
{
template<class... SubTs>
derived_view(derived<SubTs...>& original)
: Ts(static_cast<Ts&&>(original))...
{
_restoreOriginal = [&](){
((static_cast<Ts&>(original) = static_cast<Ts&&>(*this)), ...);
};
}

// Also allow construction from another derived_view
template<class... SubTs>
derived_view(derived_view<SubTs...>& original)
: Ts(static_cast<Ts&&>(original))...
{
_restoreOriginal = [&](){
((static_cast<Ts&>(original) = static_cast<Ts&&>(*this)), ...);
};
}

~derived_view()
{
_restoreOriginal();
}

private:
std::function<void()> _restoreOriginal;
};

演示:https://wandbox.org/permlink/CVkmZc7AXSkTiJZx

如果有人想使用 derived_view 并访问 derived(或 derived_view)同时。将其交到其他用户手中(这是这里的计划)迟早会导致灾难...

关于c++ - 避免将转换运算符中的拷贝复制到基类的子集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55632825/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com