2016-11-02 8 views
3

これはC++初期化子リストの構文に関する質問です。C++イニシャライザリスト機能:メンバーを初期化せずに関数を呼び出す?

メンバオブジェクトコンストラクタに引数を渡さずに、関数をイニシャライザリストから呼び出すことはできますか?

以下に示すコード例は、同様の状況から言い換えるとパラコード化されていますか?

状況

  • メンバ変数は、コンストラクタ引数として シングルトンへのポインタを取ります。
  • メンバ変数は、そのクラスを含むコンストラクタの初期化子リストによって構築されます。
  • 含まれるクラスを作成する前にシングルトンが作成されていません。

コード

#include <iostream> 

#define LOG { std::cout << __PRETTY_FUNCTION__ << std::endl; } 

namespace 
{ 

template <class T> 
class SingletonService 
{ 
public: 
    static T* Instance() { LOG; return mpT; } 
    static void InstallInstance(T* pT) { LOG; mpT = pT; } 
    static void DeleteInstance() { if (mpT) delete mpT; } 

protected: 
    static T* mpT; 
}; 

template <class T> 
T* SingletonService<T>::mpT = NULL; 

class OneOfMe 
{ 
public: 
    OneOfMe() { LOG; }; 
    virtual ~OneOfMe() { }; 
}; 

class Container 
{ 
public: 
    Container(OneOfMe* pObj) { LOG; /* Do something with pObj */ } 
    virtual ~Container() { } 
}; 

int GenerateNum() 
{ 
    return 42; 
} 

class Baz 
{ 
public: 
    Baz(int num) : mNum(num) { LOG; } 
    virtual ~Baz() { } 
protected: 
    int mNum; 
}; 

class Bar 
{ 
public: 
    Bar() : mBaz(GenerateNum()) { LOG; } // Perfectly OK to call function that is argument to member object's non-default ctor. 
    virtual ~Bar() { }; 

protected: 
    Baz mBaz; 
}; 

class Foo 
{ 
public: 
    Foo() 
     : SingletonService<OneOfMe>::InstallInstance(new OneOfMe) // Compile error 
     , mContainer(SingletonService<OneOfMe>::Instance()) { } 
    virtual ~Foo() { }; 
protected: 
    Container mContainer; 
}; 

} 

int main(int argc, char* argv[]) 
{ 
    LOG; 
    Bar bar; 

    SingletonService<OneOfMe>::InstallInstance(new OneOfMe); // This works. 
    Container container(SingletonService<OneOfMe>::Instance()); // And this works. 
    SingletonService<OneOfMe>::DeleteInstance(); 
    return 0; 
} 

コンパイルエラー

>g++ main.cpp 
main.cpp: In constructor ‘<unnamed>::Foo::Foo()’: 
main.cpp:45: error: expected class-name before ‘(’ token 
main.cpp:45: error: no matching function for call to 
‘<unnamed>::Container::Container()’ 
main.cpp:37: note: candidates are: 
<unnamed>::Container::Container(<unnamed>::OneOfMe*) 
main.cpp:35: note: 
<unnamed>::Container::Container(const<unnamed>::Container&) 
main.cpp:45: error: expected ‘{’ before ‘(’ token 

質問

CLAから関数を呼び出す構文的には可能ですssコンストラクタの初期化子リストは、メンバオブジェクトのデフォルトでないコンストラクタへの引数なしで

質問は学問好奇心のためです。私は少なくとも1つの他の解決策が含まれているクラスを作成する前に、シングルトンをインスタンス化することを知っています。

答えて

1

comma operatorを利用できます。あなたの例では

class Foo 
{ 
public: 
    Foo() 
     : mContainer((SingletonService<OneOfMe>::InstallInstance(new OneOfMe), 
         SingletonService<OneOfMe>::Instance())) 
    {} 
    virtual ~Foo(); 
protected: 
    Container mContainer; 
}; 

は、そうでない場合は、これらの代わりに一つのパラメータの2と解釈され、二つの表現の周りに追加の括弧に注意してください。

1

関数を初期化子リストから呼び出すことはできますか?メンバオブジェクトのコンストラクタに引数を渡すことなく可能ですか?

このような何かはおそらく意図したとおりに動作します:

void f() {} 

struct S { 
    S(): i{(f(), 0)} {} 
    int i; 
}; 

int main() { 
    S s; 
} 

基本的な考え方は、カンマ演算子に依存することです。この場合、関数が返す値は破棄され、メンバーの初期化には使用されません。
もちろん、データメンバーが存在するという事実を利用しているので、探しているものと正確に異なる可能性があります。

あなたはデータメンバを完全に取り除くしたい場合は、次の例のように委任コンストラクタと似たような行うことができます。

void f() {} 

class S { 
    S(int) {} 

public: 
    S(): S{(f(), 0)} {} 
}; 

int main() { 
    S s{}; 
} 

ありませんが、呼び出される関数の戻り値の型何事項。コンマ演算子を使用して、intの値をタグとして使用して、適切なコンパイラにコールをディスパッチしてから、それを破棄します。

+0

ありがとうございます。私はあなたの前にオラフの答えを得ましたが、コンマオペレーターに私を紹介してくれてありがとう。 – StoneThrow

関連する問題