下面是我编写的一些代码,用于管理C++17中不同类型的态射及其组合。
如果你有任何关于实质性简化或改进的建议,或者如果我遗漏了什么,请告诉我。
最后有一个示例,它将多个不同的态射组合在一起,然后确认最后的结果可以用于constexpr上下文。
#include
#include
#include
/// Extract the first argument type from a map.
template
constexpr A0 firstArg (R(*)(A0, As...));
/** Set theoretic morphisms **/
template
struct Homomorphism {
constexpr static T value(const S);
};
template
struct Monomorphism: Homomorphism {
constexpr static T value(const S);
};
template
struct Epimorphism: Homomorphism {
constexpr static T value(const S);
};
template
struct Endomorphism: Homomorphism {
constexpr static S value(const S);
};
template
struct Isomorphism: Monomorphism, Epimorphism {
constexpr static T value(const S);
};
template
struct Automorphism: Endomorphism, Isomorphism {
constexpr static S value(const S);
};
template,
typename T1 = std::decay_t()))>,
typename T2 = std::decay_t,
typename R = std::decay_t()))>>
struct MonomorphismComposition: Monomorphism {
static_assert(std::is_base_of_v, H1>);
static_assert(std::is_base_of_v, H2>);
static_assert(std::is_same_v);
constexpr static R value(const S &s) {
return H2::value(H1::value(s));
}
};
template,
typename T1 = std::decay_t()))>,
typename T2 = std::decay_t,
typename R = std::decay_t()))>>
struct EpimorphismComposition: Epimorphism {
static_assert(std::is_base_of_v, H1>);
static_assert(std::is_base_of_v, H2>);
static_assert(std::is_same_v);
constexpr static R value(const S &s) {
return H2::value(H1::value(s));
}
};
template,
typename T1 = std::decay_t()))>,
typename T2 = std::decay_t,
typename R = std::decay_t()))>>
struct IsomorphismComposition: Isomorphism {
static_assert(std::is_base_of_v, H1>);
static_assert(std::is_base_of_v, H2>);
static_assert(std::is_same_v);
constexpr static R value(const S &s) {
return H2::value(H1::value(s));
}
};
template,
typename T2 = std::decay_t,
typename T = std::enable_if_t, T1>>
struct EndomorphismComposition: Endomorphism {
static_assert(std::is_base_of_v, H1>);
static_assert(std::is_base_of_v, H2>);
constexpr static T value(const T &s) {
return H2::value(H1::value(s));
}
};
template,
typename T2 = std::decay_t,
typename T = std::enable_if_t, T1>>
struct AutomorphismComposition: Automorphism {
static_assert(std::is_base_of_v, H1>);
static_assert(std::is_base_of_v, H2>);
constexpr static T value(const T &s) {
return H2::value(H1::value(s));
}
};
template,
typename T1 = std::decay_t()))>,
typename T2 = std::decay_t,
typename R = std::decay_t()))>>
struct HomomorphismComposition: Homomorphism {
static_assert(std::is_base_of_v, H1>);
static_assert(std::is_base_of_v, H2>);
static_assert(std::is_same_v);
constexpr static R value(const S &s) {
return H2::value(H1::value(s));
}
};
template
struct IdentityAutomorphism: Automorphism {
constexpr static T value(const T &t) {
return t;
}
};
/** This is a monomorphism if the type of S is a subset of T, i.e. is convertible to T. **/
template
struct EmbeddingMonomorphism: Monomorphism {
static_assert(std::is_convertible_v);
constexpr static T value(const S &s) {
return s;
}
};
/*** EXAMPLE ***/
struct divby2: Automorphism { constexpr static double value(double d) { return d / 2; }};
struct embed_divby2: MonomorphismComposition, divby2> {};
struct squared: Monomorphism, Endomorphism { constexpr static int value(int i) { return i * i; } };
struct squared_embed_divby2: MonomorphismComposition {};
struct S {
explicit constexpr S(int val): val{val} {};
const int val;
};
struct s_to_int: Isomorphism { constexpr static int value(const S &s) { return s.val; } };
struct bighom: MonomorphismComposition {};
struct biggerhom: MonomorphismComposition> {};
constexpr auto sum() {
double d = 0;
for (int i = 0; i < 10; ++i)
d += biggerhom::value(S{i});
return d;
}
int main() {
for (int i = 0; i < 10; ++i)
std::cout << biggerhom::value(S{i}) << '\n';
constexpr double d = sum();
std::cout << "Sum is: " << d << '\n';
}发布于 2018-11-30 11:16:26
我的印象是,这段代码是一个更大的设计的一部分,它的范围和意图我无法完全猜出来。对不起,如果我的审查在这方面似乎有点限制性或目光短浅。
我的理解是,您希望在相当宽松的C++函数和类函数类型集上构建一个数学类型系统。这是一项崇高的事业,但我恐怕他们是如此不同的现实,它将结束在一个误解。
使用c++应用程序的定义:R(*)(A0, As...) (在firstArg签名中)。这将匹配一个函数指针,但是函数引用、lambdas、成员函数、函子、指向成员函数的指针都是合法的目标,它们不一定与此签名匹配。
还有函数重载的问题:如果foo有三个重载怎么办?R(*)(A0, As...)将匹配哪一种?(答案是没有,它根本不会编译)。
此外,与这种有力的简化相比,您还构建了一个复杂的继承树,它的语义对编译器是透明的,至少超出了参数和返回类型之间的身份:编译器将如何决定函数是否真的是一个单形?
我相信您最好使用一个更简单的设计,解偶联c++类型和数学类型,至少在一定程度上如此。
这本身就已经是一个很难解决的问题,这取决于您想要对域进行多大的限制。但是,如果您只想接受将S value(T)作为接口公开的应用程序,这肯定会更容易。那么,我建议的是提供一个更简单的模板:
template
struct Application {
using result_type = R;
using argument_type = A;
template
Application(F f) : fn(f) {}
R value(A) { return fn(a); } // no need to have it static now
std::function fn;
};然后,您可以将任何符合要求的类函数对象转换为兼容的Application:auto square = Application([](auto n) { return n * n; };。现在验证应用程序组合非常简单:std::is_same (std::is_convertible也可能是一种选择)。
形态分类我对这种无所不包的继承树有点怀疑。首先要注意的是,根据基类中的规范,简单继承不会限制派生类中的value。从endomorphism继承不会约束类公开参数类型和返回类型相同的value函数。虚拟函数会限制它,但坦率地说,多继承似乎是不必要的危险和复杂。
您可以做的是将这种类型的态射作为标记,然后用std::enable_if和std::conditional约束函数D21:
template
struct Application {
// ...
using morphism_tag = Morphism;
using result_type = std::conditional_t,
std::enable_if_t, R>,
R
>;
result_type value(argument_type);
// ...
};如果生成带有返回类型与参数类型不匹配的Application标记的Endomorphism,则代码将不会编译。
但是,我不确定它的可扩展性,也不确定我们能够执行哪些规则。
态合成有了这个基础结构,您就可以更容易地按照以下思路组合态射:
template
constexpr auto resulting_morphism(Application, Application) {
if constexpr (std::is_base_of_v && std::is_base_of_v)
return Monomorphism();
else if constexpr ( /*...*/ )
// ...
else throw std::logical_error(); // throw in constexpr context simply won't compile
)
template
constexpr auto compose(Application a1, Application a2) {
return Application([](auto arg) {
return a1(a2(arg));
});
}https://codereview.stackexchange.com/questions/208736
复制相似问题