4

集約型をテストしているときに、作成している型が本当に集約型かどうかを確認するために、boost::proto::is_aggregate を使用してみました。私はこのコードを書きました:

#include <iostream>
#include <boost\proto\traits.hpp>

struct IsAggregate
{
    IsAggregate &operator=(IsAggregate const &rhs) {}
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << boost::proto::is_aggregate<IsAggregate>() << std::endl;

    return 0;
}

そして、集約型はコピー代入演算子を定義できるため、出力が真であると予想しました(これによると:集約とPODとは何ですか、そしてそれらはどのように/なぜ特別なのですか?

しかし、出力は偽です。

また、前の回答内で集約クラスを使用しました。これは true を返すはずでしたが、代わりに false を返しました。

これは、Intel Compiler と MSVC の両方を使用して Boost 1.5.9 でテストされました。

なぜこれが起こったのかについてのアイデアはありますか?

4

1 に答える 1

6

Proto の trait は、明らかに幅広い用途を意図していません。

デフォルトでは、POD 集約を呼び出すだけで、3 つのライブラリ内部型を集約として明示的にリストします。ドキュメントで説明されている動作は、かゆみを掻くためにそこにあったことを示しています (make<>関数には、どの型がどの型に対応しT{}、どの型が対応するかを知る方法が必要でしたT())。


一歩下がって、そもそもこの特性が必要な理由を再考する必要があります. ほとんどの場合、概念チェックをより具体的にすることができます。

標準ライブラリにトレイトを追加するという提案は、広く支持されている拒否で満たされています。

私はこの特性について留保があります。is_pod や is_literal_type のような役に立たないトレイトを追加するというミスを犯しました。

私の見解では、型特性は、型の観測可能なプロパティ (「この型を波括弧初期化リストから直接初期化できますか?」など) をキャプチャする必要があり、コア言語のエフェメラ (「この型はリテラルに従いますか?」など) ではありません。コンパイラの診断を必要とするための松葉杖である型ルール?」または「この型のブレース初期化は集約初期化を実行しますか、それともコンストラクターを呼び出しますか?」)。

また、誰かが違いを観察することを心配することなく、型は集約であることと同等のコンストラクタ セットを提供することを切り替えることができるべきだと思います。

私は要件を調べ、誰にでもできる実装を行うことは難しい/不可能であると結論付けました。プログラムで対処できなかった最初の要件は、

基本クラスなし (第 10 節)

クラスに (public、empty などの) 基本クラスがないことを伝える方法はありません。

したがって、私が思いつくことができる最善のことは、近似値のみです。

template <typename T>
struct is_aggregate : std::integral_constant<bool,
        std::is_pod<T>() or
        (
                std::is_trivially_constructible<T>() 
            and std::is_trivially_destructible<T>()
            and std::is_standard_layout<T>()
            and not std::is_polymorphic<T>()
        )
    >
{ };

制限があることを考えると、少なくとも Proto の内部特性よりも / かなり / 優れており、かなりうまく機能しているようです。

警告 これは、c++11/c++14 の微妙な変更 (クラス内メンバー初期化子などに関連するもの) には対応していません。また、上記の近似を構成するために使用されるトレイトの一部には、さまざまなコンパイラ バージョン (特に MSVC を思い出す) で既知の問題があるため、このトレイトがすべての言語/ライブラリ バージョンで正確であるとは信じないでください。

Live On Coliru

#include <iostream>
#include <type_traits>
#include <string>

template <typename T>
struct is_aggregate : std::integral_constant<bool,
        std::is_pod<T>() or
        (
                std::is_trivially_constructible<T>() 
            and std::is_trivially_destructible<T>()
            and std::is_standard_layout<T>()
            and not std::is_polymorphic<T>()
        )
    >
{ };

namespace simple { // ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }
    };

    static_assert(is_aggregate<X>(), "");

    void foo() { X x { 42 }; (void) x; }
}

namespace usr_defined_ctor { // NOT ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

        X() {}
    };

    static_assert(!is_aggregate<X>(), "");

    //void foo() { X x { 42 }; (void) x; }
}

namespace defaulted_ctor { // ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

        X() = default;
    };

    static_assert( is_aggregate<X>(), "");

    void foo() { X x { 42 }; (void) x; }
}

namespace static_data_members { // ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

        X() = default;

        static const bool yeah = true;
    private:
        static const bool no = true;
    protected:
        static const std::string problem;
    };

    bool const X::yeah;
    bool const X::no;
    std::string const X::problem = "whatsoever";

    static_assert( is_aggregate<X>(), "");

    void foo() { X x { 42 }; (void) x; }
}

namespace private_non_static_data_members { // NOT ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { (void) oops; return *this; }

    private:
        bool oops;
    };

    static_assert(!is_aggregate<X>(), "");

    //void foo() { X x { 42, true }; (void) x; }
}

namespace protected_non_static_data_members { // NOT ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

    protected:
        bool oops;
    };

    static_assert(!is_aggregate<X>(), "");

    //void foo() { X x { 42, true }; (void) x; };
}

namespace have_base_class { // NOT ok
    struct B {};
    struct X : B {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }
    };

    static_assert(is_aggregate<X>(), ""); // FALSE POSITIVE: the below fails to compile

    //void foo() { X x { 42 }; (void) x; };
}

int main() { }

Coliru はこれを (静的アサートなしで) きれいにコンパイルします:

g++ -std=c++0x -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++0x -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++0x -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp
于 2015-11-11T22:07:36.990 に答える