9

FunctionWrapper次のように定義されたクラスがあるとしましょう:

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

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

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

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
};

それは「行き過ぎ」になり、(1) と同様に (2) も許可しないため、どちらも役に立ちません。

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

4

1 に答える 1

8

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

はい。あなたはすでにそれを持っています。

wrap(foo);

これが機能するためには、2 つのユーザー定義の変換が必要になりvoid(*)() --> std::function<void()> --> FunctionWrapperます: したがって、これはエラーであり、別のコンストラクターを追加しFunctionWrapperて許可しない限りエラーになります。

wrap({foo}); 

これで問題ありません。copy-list-initializing を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

同様に失敗するexplicit原因となるため、コンストラクターを作成することはできません。foo({0})ただし、別のラッパーを使用して、別の間接レイヤーを追加するだけです。

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

struct Wrapper {
    Wrapper(AnotherWrapper ) { }
};

ここではwrap(0)失敗しますが、wrap({0})wrap(Wrapper{0})はどちらも OK です。

于 2016-11-21T15:33:57.017 に答える