2017-02-07 4 views
3

私は、一時オブジェクトが少なくともconst参照を保持している一時オブジェクトと同じ長さであるかどうかをテストしたいので、この例を考えました。私は実際に名前を与える場合、codebolt通常の初期化では副作用のあるこの名前のない一時的なものに対してはコンストラクタが省略されていますが、リストの初期化はされていません。

に見えるしかし、することができますよう

#include <iostream> 

struct Test { 
    Test() { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 
    ~Test() { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 
}; 

struct Holder { 
    Holder(const Test& t):m_t(t) { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 
    ~Holder() { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 

    const Test& m_t; 
}; 

int main() { 
    Holder(Test()); 

    return 0; 
} 

しかし、私は、コンパイラが実際に全部を最適化していたことを見て非常に驚きました

にライン

Holder(Test()); 

を変更することで、一時的

それは "魔法のように"動作します:codebolt

プロットツイスト:私はC++ 11に切り替えて、Holderクラスのブレースリストの初期化を使用する場合は、コンストラクタは、私は一時的かどうかに名前を与えるかどうかに関係なく省略されていません。再びcodeboltを参照してください。

ここには何がありますか?私は、副作用のあるコンストラクタは決して切れないだろうという印象を受けていましたが、私は明らかにバージョン間で変わった重要な標準を欠いています。

誰でも私にヒントを教えてもらえますか?

+2

'Holder(Test());'は、最も厄介な構文解析の変形です。 – cpplearner

+0

ああ!私が指定した例で、名前のついた変数を使って、最も厄介な解析を考慮に入れたと思う。 –

+0

これは、最も厄介な解析を抑制する余分な括弧のペアです。 'ホルダーh(テスト());'は最も厄介な構文解析であり、 'ホルダーh((テスト)))'はそうではありません。 – Oktalist

答えて

6

Holder(Test());は、Holderを返し、0引数を受け付けるTestという名前の関数を宣言します。 gの

++以下のコード:

#include <iostream> 
#include <type_traits> 

struct Test {}; 
struct Holder { Holder(Test); }; 

template<class T> 
char const* f() { return __PRETTY_FUNCTION__; } 

int main() { 
    Holder(Test()); 
    std::cout << f<decltype(&Test)>() << '\n'; 
} 

出力:Holder(Test{});又はHolder{Test{}};

const char* f() [with T = Holder (*)()] 

容易修正が初期化のためのC++ 11の括弧を使用することです。

+0

オハイオ州、ああ、これは本当に私を得ました。私はそのような方法で宣言された関数を見たことはありません。関数宣言であるとは想像もしません。これは文法の望ましくない副作用ですか、それとも実際に使用していますか? –

+1

@skypjack C++標準で_forward declaration_というようなものはありません。 _3.1宣言と定義_を参照してください。 –

+0

@FabioA * "またはそれは実際に使用していますか?" * By * it *、関数名と引数リストのまわりのかっこを使用することを参照してください。関数ポインタを返す関数を宣言するためには少なくともそれが必要です。 – user2079303

関連する問題