【发布时间】:2015-07-08 15:15:35
【问题描述】:
在处理 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});
但偶然发现错误:
表达式必须是左值或函数指示符。
经过多次尝试,我终于想出了可以编译的代码(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?)
}
发现如果某个结构T 有一个显式构造函数(就像上面代码中的A 一样),那么就可以获取@ 类型的大括号初始化临时地址987654329@ 并将其传递给接受指针 T* 的函数,但如果它没有指针(如 B),则出现上述错误,只能通过显式解决强制转换为 T 类型。
所以问题是:为什么B 需要如此奇怪的转换而A 不需要?
更新
现在很明显,将右值视为左值是 MSVS 中的扩展/功能/错误,是否有人愿意假装它实际上是一个功能(自 2010 年以来足以让 MS 维护它)并详细说明为什么 @987654335 的临时性@ 和B 需要以不同的方式传递以满足编译器吗?一定跟A的构造函数和B的缺失有关……
【问题讨论】:
-
您没有收到“临时取地址”错误吗?尝试使用不同的编译器进行编译。
-
注意 MSVC 有一个扩展允许 result of cast to be an lvalue 这似乎是同一个问题
-
fn(&A{ 1, 2 }); fn(&B {3, 4}); fn(&(B)B{ 3, 4 });都错了
-
@BЈовић 刚刚尝试使用 g++ (GCC) 4.9.3 并得到了
testbench.cpp:23:13: error: taking address of temporary [-fpermissive] fn(&A {1, 2});和testbench.cpp:25:17: error: taking address of temporary [-fpermissive] fn(&(B) B {3, 4}); -
这只是取一个临时地址,这是一个不同的 MSVC 扩展,allows binding temps to non-const references。
标签: c++ c++11 visual-c++ casting list-initialization