8

次のコードを検討してください。

#include <vector>

struct A
{
    explicit A(int i_) : i(i_) {}
    int i;
};

int main()
{
    std::vector<int> ints;
    std::vector<A> As(ints.begin(), ints.end());
}

上記はコンパイルする必要がありますか?コンストラクターがマークされているため、そうすべきではないと感じていexplicitます。

Microsoft Visual C++ はこれに同意し、明確なエラー メッセージを表示します。cannot convert from 'int' to 'const A'; Constructor for struct 'A' is declared 'explicit'

ただし、Comeau のオンライン コンパイラを使用すると、コードは正常にコンパイルされます。

どちらが正しい?

編集:

興味深いことに、(A に an を追加した後に) に変更vectorすると、両方のコンパイラでエラーが発生します。setoperator <

ただし、とを変更vector<int>するmap<int, int>と、両方のコンパイラがコードを受け入れるようになります!vector<A>map<A, A>

4

6 に答える 6

4

GCC の STL 実装を調べたところ、同様の動作をするはずです。理由は次のとおりです。

  • a の要素は、任意の 2 つの型を受け入れ、 where is aを呼び出すvector汎用関数テンプレートによって初期化されます(少し言い換えています)。これにより、明示的な変換が可能になります。XVnew( p ) X( v )vV
  • setorの要素は、特に a が渡されることを期待するmapプライベート メンバー関数によって初期化されます。このメンバー関数は (テンプレートのメンバーである以上に) テンプレートではないため、初期値を暗黙的に変換できない場合への場合、呼び出しは失敗します。(ここでもコードを単純化しています。)_tree<T,…&gt;T const &T

標準では、コンテナを範囲で初期化するときに、明示的な変換作業や暗黙的な変換が機能しないことを要求していません。単に範囲がコンテナにコピーされることを示しています。あなたの目的には間違いなくあいまいです。

数週間前に私が抱えていたような問題を考慮して、彼らが標準をどのように洗練したかを考えると、驚くべきことにそのようなあいまいさが存在します。

于 2010-01-05T05:10:09.317 に答える
1

これは、言語仕様の問題ではなく、STL ライブラリがどのように実装されているかという問題に要約されます。言語仕様には、これが機能することを禁止するものは何もありません。また、機能することを要求するものもありません。

代入演算子を使用して暗黙の変換を試行するように stl::vector コンストラクターを作成すると、失敗します。Microsoft STL 実装では、コンストラクター呼び出しによる初期化中に戻り値の最適化を利用する可能性が高く、その場合、このコードは正常に機能します。

これが機能する唯一の理由は stl::vector コンストラクターがテンプレート化されているためであり、唯一の要件はそれが input_iterator であること、またはより正確には入力反復子に必要なすべての機能をサポートすることであることに注意することが重要です。

また、これは、クロスプラットフォーム コードを記述することがしばしば困難である理由の代表的な例であることも指摘しておきます。場合によっては、どちらのコンパイラも言語標準から必ずしも逸脱していないという問題が発生することがありますが、それでもコードは移植可能ではありません。

于 2010-01-05T03:34:50.027 に答える
1

std::vector<A> As(Iterator,Iterator)STLの特定の実装での実装方法に依存すると思います。

于 2010-01-05T00:16:57.773 に答える
0

次のコードは Comeau でコンパイルされません。

class Foo
{
public:
 explicit Foo(int bar)
 {
 }
};

class Bar
{
 void DoStuff(Foo foo){

 }
 void DoStuff2()
 {
  DoStuff(4);
 }
};

エラーメッセージ:

"ComeauTest.c", line 16: error: no suitable constructor exists to convert from "int"
          to "Foo"
    DoStuff(4);
            ^

1 error detected in the compilation of "ComeauTest.c".

したがって、初歩的なレベルでは、オンライン コンパイラは明示的なコンストラクタをサポートしています。ベクトル/イテレータと関係がある必要があります。

EDITただし、これはコンパイルされます:

Foo foo = (Foo)5;

これは明示的な変換なので、問題ありません。コモー ベクトル クラスはコンストラクターのどこかで明示的なキャストを行っていると思いますが、Microsoft のライブラリではそうではありません。

明示的なコンストラクターの詳細 - http://www.glenmccl.com/tip_023.htm

于 2010-01-05T00:23:04.017 に答える
0

はい、コンパイルする必要があります。コンストラクターが使用されていない場合、その明示性は問題になりません。

于 2010-01-05T00:37:12.520 に答える