我的问题由两部分组成:
第一部分。我是否正确认为即使最近在模板方面进行了创新,以下任务也无法在 C++ 中解决?
目标是virtually(这意味着不应该发生真正的连接)在函数调用时顺序连接两个不同类型的对象的C++ std::vector。
我的理解是这是不可行的,因为在编译时不可能生成处理不同类型对象的代码(在函数中)而不使用动态多态性。
两个部分的详细信息如下。现在是第二部分。如果向量包含相同类型的元素,解决此任务的最简单方法是什么?
我在不同的向量中有一些类的对象,并且想要一些函数来处理它们作为一个整体。我不想使用虚函数,动态内存分配既不将所有不同类型的对象(指向它们的指针)放在同一个容器中,因为在大多数代码中它们的处理方式不同,我不会支付额外的费用既不为我的课程制作复杂的界面。
下面的代码取自Evg的答案,以满足AlanBirtles的要求,在下面的评论中提供最小的可复制示例。
#include <vector>
#include <iostream>
struct A {
void foo() { std::cout << "Hey, I'm A!\n"; }
};
struct B {
void foo() { std::cout << "Hey, I'm B!\n"; }
};
void bar(???) {
???.foo();
}
int main() {
std::vector<A> va(2);
std::vector<B> vb(3);
bar(???);
return 0;
}
当然,我可以一个一个地处理所有这些向量,但是我有很多向量,这会导致代码重复,并且有在添加新类型时忘记更新此类代码的风险。
我确信对于 vector 中相同类型的元素,这可以通过包装所有这些容器并为它们提供迭代器的新容器类来完成,但是有没有更简单的方法来实现这一点?
您可以使用 可变参数包 和 折叠表达式 进行一些元编程。例如:
template<class... Ts>
void bar(Ts&... vecs) {
const auto call_foo_for_each = [](auto& vec) {
for (auto& v : vec)
v.foo();
};
(call_foo_for_each(vecs), ...);
}
void caller() {
bar(va, vb /*, ... */);
}
如果你想将它们作为单个参数传递,你可以将它们打包成一个 tuple(引用):
template<class... Ts>
void bar(std::tuple<Ts...> tuple) {
const auto call_foo_for_each = [](auto& vec ) {
for (auto& v : vec)
v.foo();
};
std::apply([&](auto&... vecs) {
(call_foo_for_each(vecs), ...);
}, tuple);
}
void caller() {
bar(std::make_tuple(std::ref(va), std::ref(vb) /*, ... */));
}
目标是在函数调用时虚拟地(这意味着不应该发生真正的连接)顺序连接两个 C++
不同类型的对象。std::vector
我的理解是这是不可行的,因为在编译时不可能生成处理不同类型对象的代码(在函数中)而不使用动态多态性。
如果所有类型在编译时都是已知的,您可以使用静态多态性来实现 - 当取消引用时,您的连接视图将返回不是底层元素而是包含
std::variant
和指向底层类型的指针的对象。
虽然不会很优雅。
但是-看到您的示例-您是否考虑过模板函数方法?如果
A
和B
都有一个方法foo
你可以
template<typename Vec>
void do_foo(Vec const & vec)
{
for(auto & element : vec)
element.foo()
}
do_foo(va);
do_foo(vb);
现在,如果出现新需求,您无需担心忘记更新其中一个向量的函数,因为它们都来自同一模板。