2016-11-12 8 views
0

私はいくつかのPODを持っていますstruct foo; struct foo { int x; unsigned y; }とします。私はstruct fooの辞書編集の順序を使って、そのフィールドの順番を比較できるようにしたい。それは私がどんなreflection voodooと私の構造体定義を飾らせずに、いくつかの一般的な方法でこれを行うことができ、私は事業者<、==、>、などの全てがstruct foo(任意の)POD C++構造体に辞書順を適用する方法は?

のために仕事をしたい、である - そしてちょうどなしこれらの演算子の定義をすべて記入してください。あるいは、これをあまりにも多くの「言語の反映に依存する」期待にする能力はありますか?

+0

メンバー以外の友人以外のオペレータが過負荷になることはありませんか?それはあなたがしたいことに最もよく聞こえます。 –

+2

標準のC++は_reflection_をサポートしていません(まだ)。 –

+2

そして、C++の単純な複雑さのために、私は包括的に役立つ方法で追加することは難しいと思います。別の方法として、http://stackoverflow.com/a/40564415/120163 –

答えて

5

これはC++ 1zで行うことができます。あなたはあなたが尋ねたように、既に定義を求め、すべての演算子を持つタプルを作成するためにtie_as_tupleを使用することができ、今

struct anything { 
    template<class T> operator T()const; 
}; 

namespace details { 
template<class T, class Is, class=void> 
struct can_construct_with_N:std::false_type {}; 

template<class T, std::size_t...Is> 
struct can_construct_with_N<T, std::index_sequence<Is...>, 
     std::void_t< decltype(T{(void(Is),anything{})...}) >>: 
                  std::true_type 
{}; 
} 

template<class T, std::size_t N> 
using can_construct_with_N=details::can_construct_with_N<T, std::make_index_sequence<N>>; 

namespace details { 
template<std::size_t Min, std::size_t Range, template<std::size_t N>class target> 
struct maximize: std::conditional_t< 
    maximize<Min, Range/2, target>{} == (Min+Range/2)-1, 
    maximize<Min+Range/2, (Range+1)/2, target>, 
    maximize<Min, Range/2, target> 
>{}; 

template<std::size_t Min, template<std::size_t N>class target> 
struct maximize<Min, 1, target>: std::conditional_t< 
    target<Min>{}, 
    std::integral_constant<std::size_t,Min>, 
    std::integral_constant<std::size_t,Min-1> 
>{}; 

template<std::size_t Min, template<std::size_t N>class target> 
struct maximize<Min, 0, target>: 
    std::integral_constant<std::size_t,Min-1> 
{}; 

template<class T> 
struct construct_searcher { 
    template<std::size_t N> 
    using result = ::can_construct_with_N<T, N>; 
}; 

template<class T, std::size_t Cap=4> 
using construct_arity = details::maximize< 0, Cap, details::construct_searcher<T>::template result >; 

template<typename T> 
constexpr auto tie_as_tuple_impl(std::integral_constant<size_t, 1>, T&& t){ 
    auto&& [a] = t; 
    return std::tie(a); 
} 

template<typename T> 
constexpr auto tie_as_tuple_impl(std::integral_constant<size_t, 2>, T&& t){ 
    auto&& [a,b] = t; 
    return std::tie(a,b); 
} 

template<typename T> 
constexpr auto tie_as_tuple_impl(std::integral_constant<size_t, 3>, T&& t){ 
    auto&& [a,b,c] = t; 
    return std::tie(a,b,c); 
} 

template<size_t S, typename T> 
constexpr auto tie_as_tuple(T&& t){ 
    return tie_as_tuple_impl(std::integral_constant<size_t, S>{}, std::forward<T>(t)); 
} 

} 

template<typename T> 
constexpr auto tie_as_tuple(T&& t){ 
    constexpr size_t S = details::construct_arity<std::decay_t<T>>::value; 
    return details::tie_as_tuple<S>(std::forward<T>(t)); 
} 

this答えに基づか、私がコンセプトの、次の証明を用意しました。

demo

Iはtie_as_tuple_implのいくつかのオーバーロード、構造体の各要素数のいずれかを準備しなければならなかったが、それは、構造体の要素の数を直線的にスケール注意。 C++ 14では


が同様のソリューションを可能性がありますmagic_getだが、それはその点に注意して、より多くの情報のためhereを参照してください。

+0

これは私を解読するのに時間がかかっていますが、構造体の要素の数を "数える"型の特性については既に+1されています - 私はまだそれが本当にうまくいくとは信じられません...また、nitpick: 「空想」よりむしろ。 – einpoklum

+0

@einpoklumその部分はYakkの実装(リンク)から盗まれています。私はそれもtypoだと思っていましたが、この時点で私は定義されたコンストラクタを持つ構造体でこの作業を行うことができるかどうかを見ています(現在can_construct_with_N がtrue型を返すにもかかわらず、 – krzaq

2

私の構造定義をリフレクション・ブードゥーにデコレートすることなく、これを一般的な方法で行うことはできますか?

いいえ、現在のC++標準で一般的な方法でこれを達成する方法はありません。

"reflection voodo"は、タイプリフレクション(まだ)をサポートしていないため、意味が分かりません。

将来的には、のような操作が辞書順にのように最初に利用可能であるという疑いがあります。


または「言語の反射依存」期待のこのあまりを行う能力のですか?

おそらくはい。あなたはC#のような言語で試してみるかもしれませんが、リフレクションがありますが、ジェネリック演算子の実装を提供するのは難しいでしょう。

+0

"reflection voodoo"とは、フィールドアドレスや、C++リフレクションパッケージが使用するフィールド名のベクトルのようなものを意味していました。 – einpoklum

+0

また、恥について、私はC#:-)に切り替えることによって侮辱することを示唆しています – einpoklum

1

は現在++(およびブーストafaics中)、標準Cで

auto operator < (const foo &a, const foo &b) { 
    return std::tie(a.x, a.y) < std::tie(b.x, b.y); 
} 

のようなものには近道はありません。

これは実際には不必要でエラーを起こすタイプの入力であるため、Defaulted comparison operatorsが提案されていますが、標準C++にはまだ追加されていません(C++の現在のドラフト17)。

+0

...しかしそのスニペット自体は正しく動作しますか?これはすでに改善されています。 – einpoklum

+0

@einpoklumええ、スニペット自体は問題ありません。 –

0

標準のC++ 11またはC++ 14ではこれを実行できません。

struct -sとその比較関数の両方を生成するプログラムやスクリプトを作成することを検討できます。おそらく、GPPまたはm4のような外部プリプロセッサを使用してください(または独自のC++ジェネレータを記述してください)。 Qt mocは感動的かもしれません。

それとも、いくつかのコンパイラプラグインを持っ検討するかもしれない(GCCを使用している場合:in C++、またはMELTでコーディングされ、Clangを使用している場合:コード化されたin C++)の仕事を支援します。 C++コンパイラは非常に複雑な獣であるため、おそらく数週間の作業が必要になるでしょう。したがって、大きなプログラムの場合にのみ価値があります。

+1

私は実際にGCCがプラグインをサポートしているか知りませんでした。面白い。 – einpoklum

関連する問題