3
我試圖編寫一個(C++ 98)程序,其中發生以下模式:我有一個非常簡單的通用元組類,並且需要用值填充它使用工廠建造。小例子,代碼如下:使用工廠填充元組並避免複製
#include <iostream>
class diagnostics
{
private:
int payload;
public:
diagnostics(int a)
: payload(a)
{
std::cout << "constructor\n";
}
diagnostics(const diagnostics& o)
: payload(o.payload)
{
std::cout << "copy constructor\n";
}
~diagnostics()
{
std::cout << "destructor [" << payload << "]\n";
}
};
struct creator
{
static diagnostics create()
{
static int i = 0;
return diagnostics(++i);
}
};
template<class Head, class Tail>
struct tuple
{
Head head;
Tail tail;
typedef Head head_t;
typedef Tail tail_t;
tuple(const Head& h, const Tail& t)
: head(h), tail(t)
{
}
};
struct empty_tuple { };
template<class Tuple, class Create>
struct create_helper
{
static Tuple create()
{
return Tuple(Create::create(),
create_helper<typename Tuple::tail_t, Create>::create());
}
};
template<class Create>
struct create_helper<empty_tuple, Create>
{
static empty_tuple create()
{
return empty_tuple();
}
};
template<class Tuple, class Create>
Tuple create()
{
//return Tuple(Create::create(), empty_tuple()); //(*)
return create_helper<Tuple, Create>::create();
}
int main()
{
typedef tuple<diagnostics, empty_tuple> tuple_t;
tuple_t a = create<tuple_t, creator>();
}
輸出是
constructor
copy constructor
destructor [1]
destructor [1]
我想擺脫中間兩行。
爲了簡化討論,我們可以在上面的代碼中取消標註(*)行的註釋;這將打破通用性而不是程序。
現在我的主要問題:我該如何解決這種情況?是否有標準防止RVO(推測RVO將不得不在這裏遞歸地完成)?如果不是,接受編譯器不夠好,有沒有一種方法可以使它以明確的方式發生?我可以將create()的callside複雜化,但我不想讓元組中的對象複雜化(特別是其中一些不能默認構造,我不想引入額外的「單元化」向他們說明)。可能安置新的可能的幫助?
以下問題似乎有關,但最終沒有幫助:Why does not RVO happen here?)
我認爲這行'return create_helper :: create();'在輸出中創建了額外的兩行。該行正在返回一個已創建的對象,然後'tuple_t a = create ();'然後使用複製構造函數複製到'a',然後破壞'create <...>()'的返回值。 。 –
abiessu
編譯器認爲您的診斷類具有不平凡的構造函數/析構函數(具有不小的副作用)並因此拒絕RVO似乎不是不合理的。請注意,該標準特別允許在複製初始化的情況下進行優化('diagnostics instance = diagnostics(...)')IIRC – sehe
最小的示例不會生成顯示的輸出,因爲沒有人調用'creator'。請添加一個'main'測試工具,它將實際生成顯示的輸出(理想情況下爲高優化級別)。 – Yakk