Моделирование симметричного c отношения типов типа (std :: plus, std :: minus) с шаблонами возможно? - PullRequest
2 голосов
/ 02 мая 2020

Можно ли определить (неупорядоченные) пары типов в c ++ (20) таким образом, чтобы можно было найти такую ​​пару, предоставив любой из ее членов во время компиляции?

Это тривиально для достижения либо вручную определяя две упорядоченные пары для каждой неупорядоченной пары, либо определяя полный набор пар в одном месте, например, в качестве параметров шаблона кортежа:

Определение пары (A, B) с помощью специализации:

template<>
struct find_pair<A> {
    using p = std::pair<A,B>;
};

template<>
struct find_pair<B> {
    using p = std::pair<A,B>;
};

Получить (A, B):

find_pair<A>::p

или

find_pair<B>::p

Определение полного набора пар с помощью variadi c шаблон:

template<typename A, typename B, typename ... X>
struct some_binary_relation : some_binary_relation<X...> {
    template<>
    static std::pair<A,B> p<A>();

    template<>
    static std::pair<A,B> p<B>();
};
using rel1 = some_relation<A,B,F,G,M,N>;
decltype(rel1::p<G>()) x //std::pair<F,G>

Преимущество подхода # 1 состоит в том, что каждое определение пары может быть сделано отдельным, но требует избыточного / раздутого синтаксиса. Подход № 2 требует, чтобы каждый тип записывался только один раз, но необходимо вручную собрать все пары в списке параметров шаблона (негибко).

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

Конечно, никакие две отдельные пары не должны содержать один и тот же тип, и поиск несуществующих пар не должен поддерживаться.

1 Ответ

0 голосов
/ 07 мая 2020

Не уверен, что вы на самом деле ищете, но это может быть полезно:

#include <utility>

namespace pair {
template<class T> struct Type {};

template<class A, class B>
struct Pair {
    Pair(Type<A>);
    Pair(Type<B>);

    using type = std::pair<A, B>;
};

} // pair

namespace detail {

void FindPairImpl(...);

template<class A>
auto FindPairImpl(pair::Type<A> a) -> typename decltype(RegisterPair(a))::type;

} // namespace detail

template<class PairedType>
using FindPair = decltype(detail::FindPairImpl(pair::Type<PairedType>()));

Точки настройки: объявите функцию Pair<Type1, Type2> RegisterPair(Pair<Type1, Type2>) в pair пространстве имен.

Затем используйте FindPair метафункция для поиска пары для типа:

namespace pair { auto RegisterPair(Pair<double, const char *> a) -> decltype(a); }

int main() {
    static_assert(std::is_same<FindPair<int>, void>::value);
    static_assert(std::is_same<FindPair<double>, std::pair<double, const char *>>::value);
    static_assert(std::is_same<FindPair<const char *>, std::pair<double, const char *>>::value);
}
...