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