отражение — Как наложить лексикографический порядок на (произвольную) структуру POD C ++?

У меня есть немного POD struct foo; Предположим, это struct foo { int x; unsigned y; }, Я хочу иметь возможность сравнивать struct fooИспользует лексикографический порядок — по порядку их полей, конечно. То есть я хочу всех операторов <, ==,> и т. д. для работы на struct foo«s

Могу ли я сделать это каким-то общим способом, не украшая мое определение структуры каким-либо отражение вуду — и не просто изложив все эти определения операторов? Или способность делать это слишком сильно зависит от «языкового отражения»?

0

Решение

Вы можете сделать это в C ++ 1z. На основе этот Ответ, я подготовил следующее доказательство концепции:

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));
}

Теперь вы можете использовать tie_as_tuple создать кортеж, в котором все опрошенные вами операторы уже определены, как вы и просили.

демонстрация

Обратите внимание, что мне пришлось подготовить несколько перегрузок tie_as_tuple_implпо одному на каждое количество элементов в структуре, но линейно масштабируется для количества элементов структуры.


В C ++ 14 есть magic_get что может позволить подобное решение, но оно имеет свои недостатки, см. Вот для дополнительной информации.

5

Другие решения

Могу ли я сделать это каким-то общим способом, не украсив свое определение структуры каким-либо отражением вуду — и просто не изложив все эти определения операторов?

Нет, нет никакого способа добиться такого общего с нынешним стандартом C ++.

Я даже не знаю, что вы имеете в виду с «отражение вудо» поскольку стандарт не поддерживает отражение типов (пока).

И даже если так в будущем, у меня есть сомнения, что такие операции, как список в лексикографическом порядке будет доступен в первую очередь.


Или способность делать это слишком сильно зависит от «языкового отражения»?

Вероятно, да. Вы можете попробовать язык, подобный c #, у которого есть отражение, но все равно будет сложно обеспечить реализацию универсального оператора.

2

Там в настоящее время нет ярлыка для чего-то вроде

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

в стандарте C ++ (и в Boost Afaics).

Поскольку это действительно ненужная и подверженная ошибкам печать, Операторы сравнения по умолчанию были предложены, но еще не добавлены в стандарт C ++ (по состоянию на текущий проект для C ++ 17).

1

Вы не можете сделать это в стандартном C ++ 11 или C ++ 14.

Вы можете рассмотреть возможность использования какой-либо программы или скрипта, генерирующих оба structи их функция сравнения. Возможно, использовать какой-то внешний препроцессор, например GPP или же m4 (или написать свой собственный генератор C ++). Qt moc может быть вдохновляющим

Или вы можете подумать о том, чтобы иметь какой-нибудь плагин компилятора (если вы используете НКУ: закодированный в C ++, или в ПЛАВИТЬСЯ; при использовании лязг: закодированный в C ++) чтобы помочь работе. Это может потребовать, возможно, нескольких недель работы (потому что компиляторы C ++ — очень сложные звери), поэтому стоит только для больших программ.

0
По вопросам рекламы [email protected]