9

のは、私はこのように定義されたクラスFunctionWrapperがあるとしましょう:暗黙的な変換を防止しますが、リストの初期化を許可しますか?

struct FunctionWrapper 
{ 
    FunctionWrapper(std::function<void()> f); 

    // ... plus other members irrelevant to the question 
}; 

私はリストの初期化を使用して、それがある(FunctionWrapperstd::function<void()>から暗黙的な変換を防ぐために好きですが、ブレースの初期化構文を使用してFunctionWrapperを構築できるようにしたいです1つの引数で)。言い換えれば、私はこれが欲しいです:

void foo(); 
void wrap(FunctionWrapper); 

wrap(foo); // (1) error 
wrap({foo}); // (2) OK 
wrap(FunctionWrapper{foo}); // (3) OK 

達成する方法はありますか?上記のクラスを定義した方法はそうではありません。暗黙的な変換が可能なので、(1)コンパイルします。

私は、コンストラクタにexplicitを追加する場合:

struct FunctionWrapper 
{ 
    explicit FunctionWrapper(std::function<void()> f); 

    // ... plus other members irrelevant to the question 
}; 

それは「行き過ぎ」行くように、それは、どちらかの助けにはならないと禁止し(2)と同様に(1)。

「中盤」を達成し、(1)エラーが発生している間に(2)コンパイルする方法はありますか?

+4

'std :: initializer_list'パラメータを取る明示的なコンストラクタを追加します。 –

+3

あなたはinitializer_listを使うことができますが、引数の数をランタイムチェックするしかないでしょう...おそらくテンプレートはconst配列とstatic_assertをテンプレートサイズで受け取ります...しかしそれはちょっと醜い – Hcorg

+0

@Hcorgは[this](http: /melpon.org/wandbox/permlink/0rFgVYD8XKYwVlC1)二重ブレースの初期化が必要ですか? –

答えて

8

これを達成する方法はありますか?

はい。あなたはすでにそれを持っています。これが機能する

wrap(foo); 

、それは2つのユーザー定義の変換伴うだろう:void(*)() --> std::function<void()> --> FunctionWrapperを、私たちは1ユーザー定義の変換にまでしか許可されています。だから、これはエラーで、それを可能にするために別のコンストラクタをFunctionWrapperに追加しないかぎりです。

wrap({foo}); 

これは、上記の制限は適用されません我々はFunctionWrapperをコピーリスト初期化している、すでに罰金です。

wrap(FunctionWrapper{foo}); 

これは明らかです。


これは、最初の例が実際に働いた場合のパスも示しています。あなたが持っていたとしましょう:

struct Wrapper { 
    Wrapper(int) { } 
}; 

foo(0);   // want this to fail 
foo({0});   // want this to be OK 
foo(Wrapper{0}); // ... and this 

ことも同様に失敗しfoo({0})の原因となるので、あなたは、コンストラクタexplicitをすることはできません。

ここ
struct AnotherWrapper { 
    AnotherWrapper(int i): i{i} { } 
    int i; 
}; 

struct Wrapper { 
    Wrapper(AnotherWrapper) { } 
}; 

wrap(0)は失敗しますが、wrap({0})wrap(Wrapper{0})は両方OKです。しかし、あなたは単に他のラッパーとの間接の別の層を追加することができます。

関連する問題