将对模板化函数的引用封装在编译时对象中
encapsulate reference to templated function inside compile time object
截至撰写本文时,metaclasses 很遗憾还不是一项功能。
我正在尝试将对模板化函数的引用封装在一些编译时对象中,理想情况下编译时对象很容易制作,类似于带有 consteval ctor 的类型。
使用非模板函数 ptr 执行此操作很简单:
template <typename T>
struct Magma { //magma trait
T (& combine)(T, T);
consteval Magma(decltype(combine) c): combine{c} {}
};
template <typename T, const Magma<T> & mag>
T add(T x, T y) {return mag.combine(x, y);}
这是一个天真的尝试使用模板函数 ptr 的示例:
template <template<typename> typename F>
struct Functor { //functor trait
template <typename A, typename B> //member template compilation error
F<B> (& map)(std::function<B(A)>, F<A>);
consteval Functor(decltype(map) m): map{m} {}
};
//...
template <template<typename>typename F, const Functor<F> & ftor>
这失败了,因为在成员模板的情况下,遗憾的是没有办法告诉编译器该类型只在编译时存在,而不是(在写作时)它会关心。
我遇到的问题:
我会使用 C++20 概念写 temp_callable_concept auto map
或类似的东西,但是 auto
不是数据成员的有效标识符。
我可能可以使用 C++20 概念将类型定义移动到 Functors
的模板中,但这违背了封装函数的要点。
我可以将 Functor
写成一个概念,并让 Functor
的“实例”成为 类 具有可见的静态成员函数以及匹配的名称和签名;但这使得“实例”难以实现。
最后的想法
我现在看不到这样做的方法,我相信这需要 C++ 允许显式编译时间类型,其数据成员签名与模板 args 相匹配。
如果有人知道封装此行为的方法,请留下答案,或者如果您有任何问题,请发表评论。
I could write Functor as a concept and have "instances" of Functor be classes with visible static member functions with matching name and signature; but that makes the "instances" obtuse to implement.
通常是这样完成的。它是 一点 笨拙的,尽管它与 haskell 中在 rust 或类型类中完成特征的方式并没有什么不同。如果你想实现 haskell Functor
例如:
template<template<typename> typename T>
struct Functor : public std::false_type {};
template<>
struct Functor<std::vector> : public std::true_type {
template<typename T, typename F>
requires (std::invocable<F, T>)
static auto fmap(std::vector<T> v, F&& f) -> std::invoke_result_t<F, T> {
// ...
}
};
template<template<typename> typename C, typename T, typename F>
requires (Functor<C>::value && std::invocable<std::remove_cvref_t<F>, T>)
auto fmap(C<T> v, F&& f) {
return Functor<C>::fmap(v, std::forward<F>(f));
}
这让您可以简单地使用它 fmap
为您提供编译时多态性,同时仍然允许类似实现的特征。实际上,您还应该制定一个概念来指定 Functor
实现的要求并使用它而不是仅仅检查任何实现(使用 value
)
截至撰写本文时,metaclasses 很遗憾还不是一项功能。
我正在尝试将对模板化函数的引用封装在一些编译时对象中,理想情况下编译时对象很容易制作,类似于带有 consteval ctor 的类型。
使用非模板函数 ptr 执行此操作很简单:
template <typename T>
struct Magma { //magma trait
T (& combine)(T, T);
consteval Magma(decltype(combine) c): combine{c} {}
};
template <typename T, const Magma<T> & mag>
T add(T x, T y) {return mag.combine(x, y);}
这是一个天真的尝试使用模板函数 ptr 的示例:
template <template<typename> typename F>
struct Functor { //functor trait
template <typename A, typename B> //member template compilation error
F<B> (& map)(std::function<B(A)>, F<A>);
consteval Functor(decltype(map) m): map{m} {}
};
//...
template <template<typename>typename F, const Functor<F> & ftor>
这失败了,因为在成员模板的情况下,遗憾的是没有办法告诉编译器该类型只在编译时存在,而不是(在写作时)它会关心。
我遇到的问题:
我会使用 C++20 概念写
temp_callable_concept auto map
或类似的东西,但是auto
不是数据成员的有效标识符。我可能可以使用 C++20 概念将类型定义移动到
Functors
的模板中,但这违背了封装函数的要点。我可以将
Functor
写成一个概念,并让Functor
的“实例”成为 类 具有可见的静态成员函数以及匹配的名称和签名;但这使得“实例”难以实现。
最后的想法
我现在看不到这样做的方法,我相信这需要 C++ 允许显式编译时间类型,其数据成员签名与模板 args 相匹配。
如果有人知道封装此行为的方法,请留下答案,或者如果您有任何问题,请发表评论。
I could write Functor as a concept and have "instances" of Functor be classes with visible static member functions with matching name and signature; but that makes the "instances" obtuse to implement.
通常是这样完成的。它是 一点 笨拙的,尽管它与 haskell 中在 rust 或类型类中完成特征的方式并没有什么不同。如果你想实现 haskell Functor
例如:
template<template<typename> typename T>
struct Functor : public std::false_type {};
template<>
struct Functor<std::vector> : public std::true_type {
template<typename T, typename F>
requires (std::invocable<F, T>)
static auto fmap(std::vector<T> v, F&& f) -> std::invoke_result_t<F, T> {
// ...
}
};
template<template<typename> typename C, typename T, typename F>
requires (Functor<C>::value && std::invocable<std::remove_cvref_t<F>, T>)
auto fmap(C<T> v, F&& f) {
return Functor<C>::fmap(v, std::forward<F>(f));
}
这让您可以简单地使用它 fmap
为您提供编译时多态性,同时仍然允许类似实现的特征。实际上,您还应该制定一个概念来指定 Functor
实现的要求并使用它而不是仅仅检查任何实现(使用 value
)