簡體   English   中英

返回其參數的函數模板上的C ++編譯器優化

[英]C++ Compiler optimization on a function template that returns its argument

使用Boost Locale / ICU,我為使用Mingw時向Windows控制台(cmd)輸出非ASCII字符的問題創建了解決方案。

現在,我決定使用Visual Studio嘗試一下,只是發現使用std::locale::global(std::local(""))會導致cmd上正確的非ASCII輸出,所以不需要我的解決方案。

現在,該代碼#error在VS上存在,但我希望它具有更高的可移植性,即在VS和Mingw上都使用該代碼,但在VS上不執行任何操作。

顯而易見的解決方案是預處理器,類似於以下內容(簡化后,我省略了諸如do {} while(0) ):

#if defined(_MSC_VER)
#define SOME_HOPEFULLY_UNIQUE_PREFIX_CONVERT_OUTPUT(x) x
#else
#define SOME_HOPEFULLY_UNIQUE_PREFIX_CONVERT_OUTPUT(x) ConvertOuput(x)
#endif

然后我想知道我是否可以使用剛剛返回其參數的函數模板來達到相同的結果。 像這樣:

template <typename T>
T ConvertOutput(T t)
{
    return t;
}

按預期,使用char*進行了一個簡單測試(MSVC Community 2015上的x64版本配置), ConvertOutput()了對ConvertOutput()的調用:

lea  rdx,[string "teste" (013F79761Ch)]  
mov  rcx,qword ptr [__imp_std::cout (013F797178h)]  
call std::operator<<<std::char_traits<char> > (013F791690h)  
mov  dl,0Ah  
mov  rcx,rax  
call std::operator<<<std::char_traits<char> > (013F791870h)  

但是,使用std::string的同一簡單測試表明,盡管我們獲得了RVO,但仍在構建一個臨時文件並調用ConvertOutput()

124: std::string b1{"teste2"};
mov  qword ptr [rsp+88h],0Fh  
mov  qword ptr [rsp+80h],0  
mov  byte ptr [b1],0  
mov  r8d,6  
lea  rdx,[string "teste2" (013F127624h)]  
lea  rcx,[b1]  
call std::basic_string<char,std::char_traits<char>,
         std::allocator<char> >::assign (013F1210C0h)  
nop  

125: auto b2 = ConvertOutput(b1);
mov  qword ptr [rsp+38h],0Fh  
mov  qword ptr [rsp+30h],0  
mov  byte ptr [rsp+20h],0  
or   r9,0FFFFFFFFFFFFFFFFh  
xor  r8d,r8d  
lea  rdx,[b1]  
lea  rcx,[rsp+20h]  
call std::basic_string<char,std::char_traits<char>,
         std::allocator<char> >::assign (013F1211F0h)  
lea  rdx,[rsp+20h]  
lea  rcx,[b2]  
call ConvertOutput<std::basic_string<char,std::char_traits<char>,
         std::allocator<char> > > (013F124090h)  
nop  

我曾希望編譯器知道所有ConvertOuput()所做的工作就是返回其參數,因此也可以在這里忽略它。 我意識到這可能是不明智的,因為任意T的復制ctor可能會有一些所需的副作用(?),但是由於實例化是通過std::string發生的,所以我希望編譯器在std類上有更多的擺動空間。

ConvertOutput()專門用於std::string得到類似的結果-如果ConvertOutput()獲取引用,則該臨時項會消失,但調用仍然存在。

作為最后的嘗試,我像這樣重載了ConvertOutput()

template <typename CharT>
CharT const* ConvertOutput(std::basic_string<CharT> const &t)
{
    cout << "Ref: " << t << '\n';
    return t.c_str();
}

最后,我得到了我期望的行為,包括對ConvertOutput()調用的ConvertOutput() /內聯:

132: std::string b1{"teste2"};
mov    qword ptr [rsp+40h],0Fh  
mov    qword ptr [rsp+38h],0  
mov    byte ptr [b1],0  
mov    r8d,6  
lea    rdx,[string "teste2" (013F697624h)]  
lea    rcx,[b1]  
call   std::basic_string<char,std::char_traits<char>,
           std::allocator<char> >::assign (013F6910C0h)  
nop  

133: auto b2 = ConvertOutput(b1);
lea    rdx,[string "Ref: " (013F697730h)]  
mov    rcx,qword ptr [__imp_std::cout (013F697178h)]  
call   std::operator<<<std::char_traits<char> > (013F691690h)  
mov    rcx,rax  
lea    rdx,[b1]  
call   std::operator<<<char,std::char_traits<char>,
           std::allocator<char> > (013F691A30h)  
mov    rcx,rax  
mov    dl,0Ah  
call   std::operator<<<std::char_traits<char> > (013F691870h)  
lea    rdx,[b1]  
cmp    qword ptr [rsp+40h],10h  
cmovae rdx,qword ptr [b1]  

我看不出有什么辦法可以達到與帶有模板的預處理器宏相同的效果,至少沒有一定數量的警告。

我錯了嗎? 是否有一種方法(簡單或其他方法)可以通過模板來實現,而不會對每個使用的類型進行重載/專門化?

怎么樣std::forward

template <typename T>
T&& ConvertOutput(T&& t)
{
    return std::forward<T>(t);
}

暫無
暫無

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

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