шаблоны — Написание классов типов в переполнении стека

Я пытаюсь написать что-то похожее на C ++ для набора классов типов, и я борюсь с тем, как упорядочить подписи шаблонов, или если вообще возможно сделать то, что я хочу сделать.

Чтобы разбить его на наименьший пример, скажем, у меня есть это:

template<typename S, typename T>
struct Homomorphism {
//Defined in specialization: static const T morph(const S&);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};

template<typename S, typename T>
struct Monomorphism : Homomorphism<S, T> {
//Defined in specialization: static const T morph(const &S);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};

У меня есть специализации этих классов (и других морфизмов) для типов данных в моей программе.

Теперь я хотел бы написать шаблон структуры, который будет принимать два гомоморфизма или два мономорфизма и составлять их для генерации новой структуры гомоморфизма или мономорфизма соответственно, то есть что-то вроде:

template<typename S, typename T, typename U,
typename HST = Homomorphism<S, T>,
typename HTU = Homomorphism<T, U>,
typename HSU = Homomorphism<S, U> >
struct CompositionMorphism : HSU {
static const U morph(const S &s) {
return HTU::morph(HST::morph(s));
}
static constexpr bool is_instance = true;
using src  = S;
using dest = U;
}

Это на самом деле работает для составления специализированных случаев гомоморфизма с помощью:

CompositionMorphism<Class1, Class2, Class3>::morph(class1Instance);

когда у меня было:

struct Homomorphism<Class1, Class2> {
static const Class2 morph(const Class1 &c) {
...
}
};

и аналог для Homomorphism<Class2, Class3>,

Теперь, однако, я хотел бы написать:

template<typename S, typename T, typename U,
typename MST = Monomorphism<S, T>,
typename MTU = Monomorphism<T, U>,
typename MSU = Monomorphism<S, U> >
struct CompositionMorphism : MSU {
static const U morph(const S &s) {
return MTU::morph(MST::morph(s));
}
static constexpr bool is_instance = true;
using src  = S;
using dest = U;
};

но неудивительно, что компилятор жалуется на двойное определение CompositionMorphism,

Есть ли способ написать CompositionMorphism и его специализации с Homomorphism а также Monomorphism так что я смогу делать такие вещи, как звонить:

template<> struct Homomorphism<Class1, Class2> { ... };
template<> struct Homomorphism<Class2, Class3> { ... };
CompositionMorphism<Class1, Class2, Class3>::morph(c1Instance);

или же:

template<> struct Monomorphism<Class1, Class2> { ... };
template<> struct Monomorphism<Class2, Class3> { ... };
CompositionMorphism<Class1, Class2, Class3>::morph(c1Instance);

или же:

template<> struct Monomorphism<Class1, Class2> { ... };
template<> struct Homomorphism<Class2, Class3> { ... };
CompositionMorphism<Class1, Class2, Class3>::morph(c1Instance);

и пусть компилятор выберет ближайший CompositionMorphism специализация основана на моей иерархии морфизма?

0

Решение

Вы можете попробовать что-то вроде написания шаблона для выбора Homomorphism или же Monomorphism основанный на SFINAE на morph функция.

template <typename S, typename T, typename = void>
struct SelectMorphism {
using type = Homomorphism<S, T>;
};

template <typename S, typename T>
struct SelectMorphism<S, T, std::enable_if_t<std::is_same_v<decltype(Monomorphism<S, T>::morph(std::declval<S>())), const T>>> {
using type = Monomorphism<S, T>;
};

Это проверит, если Monomorphism<S, T>::morph(S) вернет T, если это так, выберите Monomorphism<S, T>, Если нет, то SFINAE потерпит неудачу и по умолчанию Homomorphism<S, T>,

Тогда мы меняем CompositionMorphism использовать этот шаблон так

template<typename S, typename T, typename U,
typename HST = typename SelectMorphism<S, T>::type,
typename HTU = typename SelectMorphism<T, U>::type,
typename HSU = typename SelectMorphism<S, U>::type >
struct CompositionMorphism : HSU {
static const U morph(const S &s) {
return HTU::morph(HST::morph(s));
}
static constexpr bool is_instance = true;
using src  = S;
using dest = U;
};

Вы можете увидеть живое демо здесь этого полного рабочего примера. Это требует c++17 но может быть написано для c++11 также (немного более многословно).

#include <iostream>

template<typename S, typename T>
struct Homomorphism {
//Defined in specialization: static const T morph(const S&);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};

template<typename S, typename T>
struct Monomorphism : Homomorphism<S, T> {
//Defined in specialization: static const T morph(const &S);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};

template <typename S, typename T, typename = void>
struct SelectMorphism {
using type = Homomorphism<S, T>;
};

template <typename S, typename T>
struct SelectMorphism<S, T, std::enable_if_t<std::is_same_v<decltype(Monomorphism<S, T>::morph(std::declval<S>())), const T>>> {
using type = Monomorphism<S, T>;
};

struct Class1 {};

struct Class2 {};

struct Class3 {};

template<>
struct Monomorphism<Class1, Class2> : Homomorphism<Class1, Class2> {
static const Class2 morph(const Class1&) { std::cout << "Morphing in Mono<Class1, Class2>" << std::endl; return Class2{}; }
static constexpr bool is_instance = false;
using src  = Class1;
using dest = Class2;
};

template<>
struct Homomorphism<Class2, Class3> {
static const Class3 morph(const Class2&) { std::cout << "Morphing in Homo<Class2, Class3>" << std::endl; return Class3{}; }
static constexpr bool is_instance = false;
using src  = Class2;
using dest = Class3;
};

template<typename S, typename T, typename U,
typename HST = typename SelectMorphism<S, T>::type,
typename HTU = typename SelectMorphism<T, U>::type,
typename HSU = typename SelectMorphism<S, U>::type >
struct CompositionMorphism : HSU {
static const U morph(const S &s) {
return HTU::morph(HST::morph(s));
}
static constexpr bool is_instance = true;
using src  = S;
using dest = U;
};

int main ()
{
CompositionMorphism<Class1, Class2, Class3>::morph(Class1{});
}
1

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

Как отмечает Super, если вы проходите только T, U а также V компилятор не знает, имеет ли смысл выбирать Homomorphism или же Monomorphism,

Итак, я полагаю, вы должны пройти Homomorphism<T, U> а также Homomorphism<U, V> (Homomorphism<T, V> может быть построен) или Monomorphism<T, U> а также Monomorphism<U, V>

Если вы хотите наложить два Homomorphism или же два Monomorphism (Я имею в виду: если вы хотите исключить Monomorphism вместе с HomomorphismВы можете написать что-то следующим образом

template <typename, typename>
struct CompositionMorphism;

template <template <typename, typename> class C,
typename S, typename T, typename U>
struct CompositionMorphism<C<S, T>, C<T, U>>
{
using comp = C<S, U>;

static const U morph (const S & s)
{ return C<T, U>::morph(C<S, T>::morph(s)); }
};

и назвать это следующим образом

   Homomorphism<int, long>        h0;
Homomorphism<long, long long>  h1;
Monomorphism<int, long>        m0;
Monomorphism<long, long long>  m1;

CompositionMorphism<decltype(h0), decltype(h1)>  h2;
CompositionMorphism<decltype(m0), decltype(m1)>  m2;

// compiler error
//CompositionMorphism<decltype(h0), decltype(m1)>  hm;

Ниже приведен полный пример компиляции

#include <array>
#include <iostream>

template <typename S, typename T>
struct Homomorphism
{
//Defined in specialization: static const T morph(const S&);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};

template <typename S, typename T>
struct Monomorphism : Homomorphism<S, T>
{
//Defined in specialization: static const T morph(const &S);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};

template <typename, typename>
struct CompositionMorphism;

template <template <typename, typename> class C,
typename S, typename T, typename U>
struct CompositionMorphism<C<S, T>, C<T, U>>
{
using comp = C<S, U>;

static const U morph (const S & s)
{ return C<T, U>::morph(C<S, T>::morph(s)); }
};int main ()
{
Homomorphism<int, long>        h0;
Homomorphism<long, long long>  h1;
Monomorphism<int, long>        m0;
Monomorphism<long, long long>  m1;

CompositionMorphism<decltype(h0), decltype(h1)>  h2;
CompositionMorphism<decltype(m0), decltype(m1)>  m2;

// compiler error
//CompositionMorphism<decltype(h0), decltype(m1)>  hm;

static_assert( std::is_same<Homomorphism<int, long long>,
decltype(h2)::comp>{}, "!" );

static_assert( std::is_same<Monomorphism<int, long long>,
decltype(m2)::comp>{}, "!" );
}
1

Хорошо, иногда мне нужно немного больше думать, но это, вероятно, то, что вы ищете:

#include <type_traits>
#include <cstdint>
#include <tuple>

template<typename S, typename T>
struct Homomorphism;

template<typename S, typename T>
struct Monomorphism;

class Class1{};
class Class2{};
class Class3{};

template<> struct Homomorphism<Class1, Class2>
{
static const Class2 morph(const Class1&);
static constexpr bool is_instance = true;#
};

template<> struct Homomorphism<Class2, Class3>
{
static const Class3 morph(const Class2&);
static constexpr bool is_instance = true;
};

template<typename S, typename T>
struct Homomorphism {
//Defined in specialization: static const T morph(const S&);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};

template<typename S, typename T>
struct Monomorphism : Homomorphism<S, T> {
//Defined in specialization: static const T morph(const &S);
static constexpr bool is_instance = false;
using src  = S;
using dest = T;
};namespace details {
template<typename T, typename U, std::enable_if_t<Homomorphism<T,U>::is_instance>* = nullptr>
U morph (const T& t)
{return  Homomorphism<T,U>::morph(t);}

template<typename T, typename U,  std::enable_if_t<Monomorphism<T,U>::is_instance>* = nullptr>
U morph (const T& t)
{return  Monomorphism<T,U>::morph(t);}}

template <typename S, typename T, typename U>
class CompositionMorphism
{
public:
static U morph (const S& s)  {return  details::morph<T,U>(details::morph<S,T>(s));}
static constexpr bool is_instance = true;
};int main(int, char**)
{
Class1 c1Instance;
CompositionMorphism<Class1, Class2, Class3>::morph(c1Instance);
std::ignore = d;
}

Возможно, вы захотите создать составной морфизм Homo / Mono вручную следующим образом:

template <> class Monomorphism<Class1,Class3> : public CompositionMorphism<Class1, Class2, Class3> {};

Затем они могут быть повторно использованы CompositionMorphism автоматически.

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