#include "MassivePOD.h"
#include "DependantClass.h" // Constructor: `DependantClass(MassivePOD&)`
class ExplicitSolution
{
public:
ExplicitSolution() : m_pod{...}, m_dep{m_pod} { };
private:
MassivePOD m_pod;
DependantClass m_dep;
};
template<typename... T>
class TemplatedSolution
{
public:
template<typename... TupArgs> TemplatedSolution(TupArgs...);
private:
// Can assume in-order construction works
std::tuple<T...> m_tuple;
};
int main()
{
ExplicitSolution a{}; // Easy!
TemplatedSolution<MassivePOD, DependantClass> b{
std::forward_as_tuple(...) // Forwarded to MassivePOD constructor
, std::forward_as_tuple(???) // Forwarded to DependantClass constructor
}; // Hard?
}
我希望这个例子说明我的问题。我想在构建整个std::tuple
之前引用之前构建的std::tuple
成员。有一个优雅的解决方案吗?我知道可能使用void *
hackery,但我宁愿在沿着那条黑暗的孤独之路寻求帮助。
我尝试过制作get_ref
函数,但我遇到的问题是我无法访问尚未创建的对象的成员函数。不过,这是我的一次尝试。
#include <tuple>
#include <utility>
class Foo // simplified base-case
{
public:
constexpr Foo(int x, char y, int& z) : m_tup{x, y, z*5.0} { };
constexpr int& get_int() { return std::get<0>(m_tup); };
constexpr char& get_char() { return std::get<1>(m_tup); };
constexpr double& get_double() { return std::get<2>(m_tup); };
private:
std::tuple<int, char, double> m_tup;
};
int main()
{
auto super = Foo(5, 'a', ::get_int()); // ???
}
然后我想也许我可以做std::function
对std::place_holders
所做的事情,所以一个静态对象包含指向std::tuple
的每个元素的指针/引用。我认为这值得尝试,但我不知道如何在实践中实施它......
答案 0 :(得分:1)
另一个建议:元组类,而不是为成员的构造函数提供参数,而是接受接收正在构造的实例并返回成员的函数。然后,这些函数可以通过getter引用先前构造的成员。您所要做的就是确保早期成员的getter工作,如果在构造后面的成员时调用,则不会调用未定义的行为。
这是一个硬编码的示例,用于演示原理的两个元素。我将留给您使用n
元素。请注意,基本上你会在这里重新实现一个元组 - 我不确定你是否可以使用现有的std::tuple
执行此操作。
template<typename A, typename B>
class TemplatedSolution
{
public:
template<typename AF, typename BF> TemplatedSolution(AF af, BF bf)
: a(af(*this))
, b(bf(*this))
{
}
A& get_first() {
return a;
}
B& get_second() {
return b;
}
private:
A a;
B b;
};
用法:
typedef TemplatedSolution<MassivePOD, DependantClass> ClassT;
ClassT b{
[](ClassT& res) { return MassivePOD(); },
[](ClassT& res) { return DependantClass(res.get_first()); },
};
由于返回值优化,MassivePOD
将在TemplatedSolution
实例中构建。
一个完整的示例,它不会显示副本here。
答案 1 :(得分:0)
如何使用std::shared_ptr
并将其作为std::shared_ptr
存储在TupleWrapper
呢?
auto p_first_member_tmp = std::make_shared<MassivePOD>(
std::forward_as_tuple(...));
TupleWrapper<std::shared_ptr<MassivePOD>, DependantClass> wrapper{
p_first_member_tmp,
std::forward_as_tuple(*p_first_member_tmp, ...)}
这是一个额外的间接层,但是你的昂贵的复制或移动结构至少不会被复制或移动。
我在考虑为什么这在Python这样的语言中永远不会成为一个问题,因为对象只创建一次,然后其他所有东西都指向它 - 这里用这种方法近似。您还不必保留对象生命周期的任何其他跟踪,因为shared_ptr
已经为您做了这些。