[英]C++ Higher order templates
I'm trying to create a system in C++ where I can implement many different entities E each with a different type T associated to them.我正在尝试在 C++ 中创建一个系统,在那里我可以实现许多不同的实体 E,每个实体都具有与之关联的不同类型 T。 I want to make a generic owner for these so that for implementations E1 associated to T1, E2 associated to T2 ect, I can wrap them inside a container where they can all be managed, something like (in pseudocode)我想为这些创建一个通用所有者,以便对于与 T1 相关联的 E1、与 T2 相关联的 E2 等实现,我可以将它们包装在一个容器中,在那里它们都可以被管理,就像(在伪代码中)
E<ConcreteT1> e1;
E<ConcreteT2> e2;
//...
Container c;
c.add(e1)
c.add(e2)
//...
I'm a beginner in C++ and I'm aware of basic templates, but I think I need some kind of 'higher order template' where the top level (C) is generic over the middle level (E) which is in turn generic over subsequent levels.我是 C++ 的初学者,我知道基本模板,但我认为我需要某种“高阶模板”,其中顶层 (C) 是通用的,而中间层 (E) 又是通用的在随后的水平。 Maybe this is a total anti-pattern and I'm doing something completely wrong.也许这是一个完全的反模式,我做错了。 Please let me know how to solve this problem.请让我知道如何解决这个问题。 I'm happy to use C++17 features but I would rather avoid the latest and greatest C++20 if possible.我很高兴使用 C++17 功能,但如果可能的话,我宁愿避免使用最新最好的 C++20。
Thank you谢谢
EDIT: The actual problem I'm trying to solve is to have an interface taking a generic E (event) in some of the methods.编辑:我要解决的实际问题是在某些方法中具有一个采用通用 E (事件)的接口。
template <typename E>
class Interface{
method(E e){...}
}
I want to implement many concretions (event handlers) each with their own E (kind of events)我想实现许多混凝土(事件处理程序),每个都有自己的 E(事件类型)
class EOne{}
class ImplOne:Interface<EOne>{
method(Eone e){...}
}
class ETwo{}
class ImplTwo:Interface<ETwo>{
method(ETwo e){...}
}
and then manage these in some more containers, say Container c
as above.然后在更多的容器中管理这些,比如上面的Container c
。 Then I will have a queue of callables where the callables may call methodN with the respective event types.然后我将有一个可调用对象队列,其中可调用对象可以使用相应的事件类型调用 methodN。
for(auto &handler:container){
eventQueue.pop()();
}
I know I'm probably going down the wrong road here.我知道我可能在这里走错了路。
You could use a std::variant
and use visitation.您可以使用std::variant
并使用访问。
Eg.例如。 the queue object could be defined as队列 object 可以定义为
using InterfaceVar = std::variant<Interface<E1>, Interface<E2>>;
std::queue< InterfaceVar > eventQueue;
Then you would use visitation to discriminate on the type (It sounds like you want it this way).然后你会使用访问来区分类型(听起来你想要这样)。 You could use std::visit
for this or your own method of visitation.您可以为此使用std::visit
或您自己的访问方法。
Example from cppreference :来自 cppreference 的示例:
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
// the variant to visit
using var_t = std::variant<int, long, double, std::string>;
// helper constant for the visitor #3
template<class> inline constexpr bool always_false_v = false;
// helper type for the visitor #4
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main() {
std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
for(auto& v: vec) {
// 1. void visitor, only called for side-effects (here, for I/O)
std::visit([](auto&& arg){std::cout << arg;}, v);
// 2. value-returning visitor, demonstrates the idiom of returning another variant
var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;}, v);
// 3. type-matching visitor: a lambda that handles each type differently
std::cout << ". After doubling, variant holds ";
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>)
std::cout << "int with value " << arg << '\n';
else if constexpr (std::is_same_v<T, long>)
std::cout << "long with value " << arg << '\n';
else if constexpr (std::is_same_v<T, double>)
std::cout << "double with value " << arg << '\n';
else if constexpr (std::is_same_v<T, std::string>)
std::cout << "std::string with value " << std::quoted(arg) << '\n';
else
static_assert(always_false_v<T>, "non-exhaustive visitor!");
}, w);
}
for (auto& v: vec) {
// 4. another type-matching visitor: a class with 3 overloaded operator()'s
std::visit(overloaded {
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.