sun*_*oon 3 c++ casting visual-c++ c++11 list-initialization
我试图通过替换两个不同的双线程来处理Windows API时使代码变得不那么臃肿
TEMP t{0,1,2}; // let's say it's struct TEMP {int a; int b; int c}
SomeVeryVerboseFunctionName(&t);
与单行
SomeVeryVerboseFunctionName(&TEMP{0,1,2});
但偶然发现错误:
expression必须是左值或函数指示符.
经过多次尝试,我终于想出了编译的代码(MSVS 2013u4):
SomeVeryVerboseFunctionName(&(TEMP) TEMP{0,1,2});//explicit cast to the same type!
为了更好地理解为什么需要演员,我设置了一个简单的测试项目:
#include <stdio.h>
struct A
{
    int a;
    int b;
    A(int _a, int _b) : a(_a), b(_b) {};
};
struct B
{
    int a;
    int b;
};
template <typename T> void fn(T* in)
{
    printf("a = %i, b = %i\n", in->a, in->b);
}
int main()
{
    fn(&A{ 1, 2 });      //OK, no extra magick
    /*  fn(&B {3, 4});      //error: expression must be an lvalue or function designator */
    fn(&(B)B{ 3, 4 });  //OK with explicit cast to B (but why?)
}
并发现如果某个struct T 有一个显式构造函数(如A上面的代码中的has),则可以获取类型为brace-initialized的临时地址T并将其传递给带有指针的函数T*,但如果不是有一个(像B),然后出现所述错误,只能通过显式转换来键入T.
所以问题是:为什么B需要这种奇怪的铸造而A不是?
现在很明显,将左值作为左值处理是MSVS中的扩展/特征/错误,是否有人担心假装它实际上是一个特征(足以用于MS自2010年以来维护它)并详细说明为什么临时A和B需要通过它以不同的方式来满足编译器?它必须与A的构造函数有关,B缺乏它...
Geo*_*ard 12
你在做什么在C++中实际上是非法的.
Clang 3.5抱怨:
23 : error: taking the address of a temporary object of type 'A' [-Waddress-of-temporary]
fn(&A {1, 2}); //OK, no extra magick
   ^~~~~~~~~
25 : error: taking the address of a temporary object of type 'B' [-Waddress-of-temporary]
fn(&(B) B {3, 4}); //OK with explicit cast to B (but why?)
   ^~~~~~~~~~~~~
所有操作数&必须是左值,而不是临时值.MSVC接受这些结构的事实是一个错误.根据Shafik上面指出的链接,似乎MSVC错误地为这些创造了左值.
template<class T>
T& as_lvalue(T&& t){return t;}
// optional, blocks you being able to call as_lvalue on an lvalue:
template<class T>
void as_lvalue(T&)=delete;
将使用合法的C++解决您的问题.
SomeVeryVerboseFunctionName(&as_lvalue(TEMP{0,1,2}));
从某种意义上说,as_lvalue是一个反向的move.你可以打电话给它unmove,但这会让人感到困惑.
在C++中取rvalue的地址是非法的.以上将rvalue变为左值,此时地址变为合法.
取rvalue的地址是非法的原因是这些数据意味着被丢弃.指针仅在当前行结束时保持有效(禁止通过左值的转换创建rvalue).这样的指针只有角落有用的东西.但是,对于Windows API,许多此类API都会指向数据结构以进行C样式版本控制.
为此,这些可能更安全:
template<class T>
T const& as_lvalue(T&& t){return t;}
template<class T>
T& as_mutable_lvalue(T&& t){return t;}
// optional, blocks you being able to call as_lvalue on an lvalue:
template<class T>
void as_lvalue(T&)=delete;
template<class T>
void as_mutable_lvalue(T&)=delete;
因为更可能是正确的,所以返回const对数据的引用(为什么要修改临时?),较长的(因此不太可能使用)返回非const版本.
MSVC有一个旧的"bug"/"特性",它将许多东西当作左值处理,当它不应该时,包括演员表的结果.使用/Za禁用该扩展.这可能导致其他工作代码无法编译.它甚至可能导致工作代码无法工作并仍然编译:我没有证明相反.
| 归档时间: | 
 | 
| 查看次数: | 228 次 | 
| 最近记录: |