C++高阶模板

C++ Higher order templates

本文关键字:高阶模 C++      更新时间:2023-10-16

我正试图在C++中创建一个系统,在那里我可以实现许多不同的实体E,每个实体都有不同的类型T。我想为这些创建一个通用所有者,这样对于与T1相关联的E1、与T2相关联的E2等实现,我可以将它们封装在一个容器中,在该容器中可以管理它们,类似于(伪代码(

E<ConcreteT1> e1;
E<ConcreteT2> e2;
//...
Container c;
c.add(e1)
c.add(e2)
//...

我是C++的初学者,我知道基本模板,但我认为我需要某种"高阶模板",其中顶层(C(是通用的,而中层(E(则是通用的。也许这完全是一种反模式,我做的事情完全错了。请让我知道如何解决这个问题。我很乐意使用C++17功能,但如果可能的话,我宁愿避免使用最新和最棒的C++20。

谢谢

编辑:我试图解决的实际问题是,在一些方法中有一个接受泛型E(事件(的接口。

template <typename E>
class Interface{
method(E e){...}
}

我想实现许多具体化(事件处理程序(,每个具体化都有自己的E(事件类型(

class EOne{}
class ImplOne:Interface<EOne>{
method(Eone e){...}
}
class ETwo{}
class ImplTwo:Interface<ETwo>{
method(ETwo e){...}
}

然后在更多的容器中管理这些,比如上面的Container c。然后我将有一个可调用的队列,其中可调用的可以调用具有相应事件类型的methodN。


for(auto &handler:container){
eventQueue.pop()();
}

我知道我可能走错了路。

您可以使用std::variant并使用访问。

例如。队列对象可以定义为

using InterfaceVar = std::variant<Interface<E1>, Interface<E2>>;
std::queue< InterfaceVar > eventQueue;

然后你会用访问来区分类型(听起来你想要这样(。您可以使用std::visit或您自己的访问方法。

来自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);
}
}