1

ノードに 2 つの子があるか、ラベル付きの葉である二分木に従うことを検討してください。このコードは g++ 4.7.2 でコンパイルされます。

#include <memory>
using namespace std;

struct Tree {
    unique_ptr<Tree> left, right;
    char label;

    Tree(char label) : label(label) {}

    Tree(Tree && left, Tree && right) :
        left(new Tree(move(left))), 
        right(new Tree(move(right))) {}

    //~ explicit Tree(Tree && left, bool right) {}

} tree {{1, 2}, 3};

明示的なコンストラクターのコメントを外すと、コンパイルに失敗します (この明示的なコンストラクターがプライベートの場合も失敗します)。これはgccのバグですか、それとも明示的なコンストラクターは、同じ数の引数を持つ非明示的なものの初期化子リスト構築の使用を禁止していますか?

編集: s/implicit/non-explicit/. 混乱して申し訳ありませんが、「暗黙的な変換を許可する」という意味で「暗黙的」という言葉を使用し、「明示的なキーワードでマークされている」という意味で「明示的」という言葉を使用しました。コンパイラによって自動的に生成されたコンストラクターを「デフォルト」と呼んでいるので、「暗黙的」という言葉がそれほどあいまいになることに気づきませんでした。

4

2 に答える 2

4

あなたの質問は、真実ではない何かを想定しているようで、根本的な誤解を明らかにしています。

まず、暗黙的に生成されたコンストラクターは、「初期化リストを使用する場合」に非表示になりません。コンストラクターをマークするかどうかに関係なく、コンストラクターを定義するたびに、それらの生成は単に禁止されますexplicit

ただし注意してください: 通常、「暗黙の」コンストラクターが意味するのは、何も指定しない場合にコンパイラーによって暗黙的に (自動的に) 生成されるコンストラクターであり、explicit修飾子がないコンストラクターではありません。上の段落では前者について話していましたが、あなたは後者について考えているように思われます。

これが事実であると仮定すると、初期化子リストを使用しているかどうかにかかわらず、としてマークされていないコンストラクターが一般的explicitにとしてマークされているコンストラクターによって隠されているというのは真実ではありません。explicit

あなたのプログラムがコンパイルされない理由は、あなたのコンストラクターが 2 番目の引数としてa を受け入れ、引数 に一致するための標準的な変換のみを必要とするためexplicit、たまたま非コンストラクターよりも適切に一致するためです。一方、を受け入れる非コンストラクターには、一時オブジェクトの構築を含むユーザー定義の変換が必要であり、標準の変換はユーザー定義の変換よりも優先されます。explicitbool2explicitTree&&Tree

に変換するのではなくTree、引数からテンポラリを構築するようにコンパイラに強制する(したがって、非コンストラクタを呼び出す) には、コンストラクタの呼び出しを次のように変更して、これを指定する必要があります。22boolexplicit

struct Tree
{
    ...
} tree {{1, Tree(2)}, 3}; // Explicitly specify the second argument is to be
                          // used to create a temporary Tree object, rather
                          // than being converted to a bool

また、トップレベル ツリーの作成にも同じことが当てはまりますが (つまり、同様3に に変換され、コンストラクタが再度呼び出されます)、オブジェクトを直接初期化しているため、この場合は問題になりません。であり、暗黙的な変換は試行されません。boolexplicittree

于 2013-02-16T18:45:41.243 に答える
0

問題の解決策は次のとおりです。

template<
  typename Bool,
  typename=typename std::enable_if<
    std::is_same<
      typename std::decay<Bool>::type,
      bool
    >
  >::type
>
explicit Tree(Tree && left, Bool&& right) {}

ここで、バリアント以外の型からの変換がbool2 番目の引数として渡されるのをブロックしました。

ただし、このコンストラクターが実行したいことを実行する静的メソッドを作成する方が、問題に対してさらにオーバーロードされたコンストラクターをスローするよりも優れている場合があります。

于 2013-02-16T19:24:11.397 に答える