3

これは私が混乱する小さな問題です。説明の仕方がわからないので、以下のコードを参照してください。

struct B {
  B() {}
  B(B&) {
    std::cout << "not trivial\n";
  }
};

int main() {
  B b1;
  B b2(b1);
  std::cout << std::is_trivially_constructible<B,  B&>::value << '\n';
  return 0;
}

出力は次のとおりです。

not trivial
1

私はVS11を使用しています。

編集:

http://en.cppreference.com/w/cpp/types/is_constructibleの例をテストしました。出力の一部が正しくありません。

#include <iostream>
#include <type_traits>
 
class Foo {
    int v1;
    double v2;
 public:
    Foo(int n) : v1(n), v2() {}
    Foo(int n, double f) : v1(n), v2(f) {}
};
int main() {
    std::cout << "Foo is ...\n" << std::boolalpha
              << "\tTrivially-constructible from const Foo&? "
              << std::is_trivially_constructible<Foo, const Foo&>::value << '\n'
              << "\tTrivially-constructible from int? "
              << std::is_trivially_constructible<Foo, int>::value << '\n'
              << "\tConstructible from int? "
              << std::is_constructible<Foo, int>::value << '\n'
}

出力は次のとおりです。

Foo is ...
        Trivially-constructible from const Foo&? true
        Trivially-constructible from int? true//Trivially-constructible from int? false
        Constructible from int? true
4

2 に答える 2

4

最終更新

@SebastianRedl による非常に洞察に満ちたコメントの後、標準の意図は、コンストラクター内の操作だけでなく、オブジェクトの構築全体を参照することであることに気付きました。これは、実際に Visual C++ にバグがあることを意味します。ただし、標準の文言が十分に明確ではないというのが私の見解であるため、残りの回答は後世のためにそのままにしておきます。

明確にするために:OPで言及されている動作は実際にはバグであり、これに照らして、この更新の下で私が言うことのほとんどは間違っています.

更新終了

これは実際にはコンパイラのバグではなく、標準の奇妙な癖であるため、混乱は理解できます。

C++11 標準によると、is_trivially_constructible::valueto beの条件は次のとおりですtrue

§20.9

is_constructible<T,Args...>::valueは true であり、is_constructible以下で定義される の変数定義は、自明ではない操作を呼び出さないことが知られています。

したがって、is_trivially_constructible指定された型が指定された引数で構築可能であり、重要な操作を呼び出さない限り、真です。あなたの例には、そのようなコンストラクター、コピーコンストラクターのみが含まれています。実際、「非自明な操作」(本質的に非自明な演算子またはコンストラクター)の定義により、これはあなたの型に当てはまります。だから返すtrueのが正解。

ただし、非常に奇妙な点が 1 つあります。C+11 標準では、コピー コンストラクターについて次のように規定されています。

§12.8.12 (強調鉱山)

クラス Xのコピー/移動コンストラクターは、それがユーザー提供でなく、

  • クラス X には仮想関数 (10.3) も仮想基本クラス (10.1) もありません。
  • 各直接基底クラスのサブオブジェクトをコピー/移動するために選択されたコンストラクターは自明であり、
  • クラス型 (またはその配列) である X の非静的データ メンバーごとに、そのメンバーをコピー/移動するために選択されたコンストラクターは自明です。

    それ以外の場合、コピー/移動コンストラクターは自明ではありません。

ユーザー定義のコピーコンストラクターを提供するため、クラスは自明にコピー構築可能ではありません。あなたが与えたコピーコンストラクターは簡単ではありません。それでも、重要なコピー コンストラクター、コピー コンストラクターに一致する引数が与えられた場合is_trivially_constructibleに返されるために必要な基準を満たしています。true

私の考えでは、これは標準の「バグ」のようです。is_trivially_constructible特定の引数を与えられた型が自明に構築可能かどうかを返します。これは、コンストラクター自体が自明であると見なされることを保証するものではないようです!

アップデート:

この次のケースを示すテストを考案しようとした後、VC11 にバグが見つかりました。標準で記述されているロジックは、Bが別の型のサブオブジェクト (メンバーまたはベース) として使用される場合、 のコピー コンストラクターを呼び出すその型のコンストラクターは、によって非自明Bであると見なされる必要があることを意味します。これはVC11には当てはまりません。std::is_trivially_constructible

サンプルコード

#include <iostream>
#include <type_traits>

struct B 
{
  B() {}
  B(B&) {
    std::cout << "not trivial\n";
  }
};

struct A : B
{
  A(B& B) : b(B){}
    B b;
};

int main() 
{
  std::cout << std::is_trivially_constructible<B,  B&>::value << '\n'; // Should print 1
  std::cout << std::is_trivially_constructible<A,  B&>::value << '\n'; // Should print 0
  getchar();
  return 0;

}

于 2013-04-26T09:55:36.073 に答える
1

http://en.cppreference.com/w/cpp/types/is_constructibleから:

「コンストラクター式は、自明ではない操作を呼び出しません」。そして、それはあなたが書くときのケースです

B(B&);

そこには特別なことは何もありません。参照を渡すだけです。

于 2013-04-26T09:08:28.190 に答える