簡體   English   中英

在構造過程中使用 std::tuple 成員引用?

[英]Use std::tuple member references during construction?

#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 是可能的,但我寧願在走那條黑暗孤獨的道路之前尋求一些幫助。

想法1

我試過創建一個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()); // ???
}

演示

想法2

然后我想也許我可以做一些類似於std::functionstd::place_holders ,所以一個靜態對象包含一個指向std::tuple每個元素所在位置的指針/引用。 我認為這值得一試,但我不知道如何在實踐中實現它......

另一個建議:元組類,而不是為成員的構造函數接受參數,而是接受接收正在構造的實例並返回成員的函數。 這些函數然后可以通過 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實例中正確構造。

此處提供一個完整的示例,它演示了沒有副本。

使用std::shared_ptr並將其存儲為TupleWrapperstd::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已經為您完成了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM