[英]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.