簡體   English   中英

如何將“非平凡可復制對象”傳遞給GCC中的varargs函數

[英]How does one pass “non trivially copyable objects” into a varargs function in GCC

我有一個自定義記錄器,該記錄器使用logger-> logf(format,...)樣式varargs方法進行記錄。 我有對象句柄是指針包裝。 我有一個特殊的格式說明符來打印對象(使用類似於Java中的toString()方法)

“句柄”不是“普通可復制”的,因為它們可以由多種輸入類型構成,並且具有轉換器轉換運算符,這些運算符將指針返回到所包含的對象類型。 (類似於ComPtr <>)

在Windows C ++中,我可以只傳遞句柄,而varags方法可以看到指針。 GCC現在認為這是一個錯誤。 句柄是“ sizeof(void *)”

有沒有辦法讓GCC在varags方法上允許它? 有沒有一種方法可以指定要傳遞給varargs方法的特殊運算符xx()方法?

我有一個很大的庫,里面有很多日志行,而用運算符+或運算符<<重做所有這些將是一件繁瑣的事情。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

好吧,如果確實需要使用Variadic模板,但是我還沒有弄清楚如何使它簡單而優雅。

算法的本質是

將對象或緩沖區放置在堆棧上(最好基於參數的數量)將所有參數添加到對象。 在最后一個參數上,也將其添加到對象中並處理參數。

可變參數模板的“遞歸”性質是一種很好的方法,可以對此進行一點了解。

好吧,我咬緊牙關,重寫了格式化程序部分以使用可變參數模板。 確實花了3天。 基本上,它涉及到具有一個“ Arg”類,該類具有所有原始類型的並集,並由構造函數重載為每種類型設置一個“ type”字段。

然后是一個可變參數模板,用於“加載args列表”,該參數傳遞給等效於“ vsprintf”的格式化程序。 很好,因為有足夠的信息可以確保運行時類型安全。 現在的問題是,隨着模板擴展,代碼膨脹多少。 正如它們所做的一樣,“ Arg”是固定大小的,其構造函數僅加載兩個字段,即type和value。 GCC和MSC會很好地優化所有參數,因此可變參數模板沒有2 ^ maxArgs個完整擴展。

 template <typename... Args> int writef(const wchar_t *fmt, ...) { FormatfArglist<sizeof...(Args)> arglist; FormatfArgBase::addArgs(arglist.args(), args...); return(vwritef(fmt, arglist)); } template <typename First, typename... Rest> static void FormatfArgBase::addArgs(Arg *arglist, const First &first, const Rest &... rest) { setArg(arglist,Arg(first)); if(sizeof... (Rest) > 0) { addArgs(++arglist, rest...); // recursive call using pack expansion syntax } } 

似乎C ++人士對舊的C省略號有很多限制,實際上必須使用Variadic模板來獲得全部功能。

因此,我硬着頭皮改寫了格式化程序部分,以使用可變參數模板。 確實花了3天。 基本上,它涉及到具有一個“ Arg”類,該類具有所有原始類型的並集,並由構造函數重載為每種類型設置一個“ type”字段。

然后是一個可變參數模板,用於“加載args列表”,該參數傳遞給等效於“ vsprintf”的格式化程序。 很好,因為有足夠的信息可以確保運行時類型安全。 現在的問題是,模板擴展中有多少代碼膨脹。 正如它們所做的一樣,“ Arg”是固定大小的,其構造函數僅加載兩個字段,即type和value。 GCC和MSC是否會很好地優化所有參數,以使可變參數模板沒有2 ^ maxArgs個完整擴展?

// This is in a "TextWriter" class
template <typename... Args>
int writef(const wchar_t *fmt, ...) {
    FormatfArglist<sizeof...(Args)> arglist;
    FormatfArgBase::addArgs(arglist.args(), args...);
    return(vwritef(fmt, arglist));
}

template <typename First, typename... Rest> 
static void FormatfArgBase::addArgs(Arg *arglist, 
                          const First &first, const Rest &... rest) {            
    setArg(arglist,Arg(first));            
    if(sizeof... (Rest) > 0) {
        addArgs(++arglist, rest...); // recursive call using pack expansion syntax  
    }
}  

我不確定為什么它可以與Microsoft編譯器一起使用。 該標准清楚地表明,

僅允許使用算術,枚舉,指針,成員指針和類類型參數。

http://en.cppreference.com/w/cpp/language/variadic_arguments )。

對於您的特定情況,我建議您使用可變參數模板函數作為將這些值轉換為指針的中間步驟,然后調用Log函數(我想這不能是模板本身)。

暫無
暫無

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

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