Windows API を扱うときに、似ていない 2 ライナーを置き換えることで、コードの肥大化を抑えようとしていました。
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
上記のコードのように)、ブレースで初期化された一時的な型のアドレスを取得T
し、それをポインターを取る関数に渡すことができることがわかりましたT*
が、そうでない場合( のような)がB
ある場合、上記のエラーが発生し、 type への明示的なキャストによってのみ克服できますT
。
問題は、なぜ がB
そのような奇妙なキャストを必要とし、A
そうでないのかということです。
アップデート
rvalue を lvalue として扱うことは MSVS の拡張機能/機能/バグであることが明らかになったので、実際に機能であるふりをしたい人はいますか (2010 年以降、MS がそれを維持するのに十分に使用されていますA
) B
。コンパイラを満足させるためにさまざまな方法で?AのコンストラクターとBのコンストラクターの欠如と関係があるに違いありません...