2016-02-26 107 views
1

使用Boost语言环境/ ICU,我为使用Mingw时将非ASCII字符输出到Windows控制台(cmd)的问题创建了一个解决方案。函数模板上的C++编译器优化返回参数

现在,我决定使用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*一个简单的测试就如预期(64位版本配置上MSVC社区2015年),到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的副本可能会有一些期望的副作用(?),但由于实例化发生在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] 

我可以没有办法像模板一样获得与预处理器宏相同的效果,至少不是没有相当多的注意事项。

我错了吗?有没有一种方法(简单或其他)来实现这一点与模板,没有重载/专门针对每个使用的类型?

+0

为什么需要这个? – Barry

+0

@Barry我需要在mingw上的转换代码在Windows控制台上输出像“Opção”这样的字符串,并且我想在VS上使用相同的客户端代码(除了不需要转换任何内容外),因此需要一些能够返回收到的参数的东西。 – PCaetano

回答

4

如何std::forward

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

@巴里:确实。 – Jarod42

+0

这绝对有效。它执行'CharT const *'版本不支持的副本(因为该版本优化了'b2'),但它允许我使用一个通用函数。 – PCaetano

+0

如果你消耗了输入,'std :: move(t)'可能更合适。但用'auto b2 = b1;'你做一个副本。 – Jarod42