返回其参数的函数模板上的C ++编译器优化

时间:2016-02-26 14:47:02

标签: c++ templates

使用Boost Locale / ICU,我为使用Mingw时输出非ASCII字符到Windows控制台(cmd)的问题创建了一个解决方案。

现在,我决定使用Visual Studio,只是发现使用std::locale::global(std::local(""))将导致cmd上的正确非ASCII输出,因此不需要我的解决方案。

目前,VS上的代码#error,但我希望它更具可移植性,即在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社区2015上的x64版本配置),对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()电话的省略/内联:

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]  

我看不到与模板的预处理器宏相同的效果,至少没有相当多的警告。

我错了吗?是否有一种方法(简单或其他方式)使用模板实现此目的,而不对每种使用的类型进行重载/专门化?

1 个答案:

答案 0 :(得分:4)

std::forward

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