由其他变量确定的cpp矢量类型

  • 本文关键字:cpp 类型 其他 变量 c++
  • 更新时间 :
  • 英文 :


假设我有两种处理值的方法,CumSum和CumProd;我有一个字符串来决定将使用哪种方法,选择。它们都在一个类中,选择是一个类的论点。CumSum和CumProd是一个为每个向量进行累积计算的类。

#include <vector>
#include <iostream>
#include <cmath>
struct CumSum {
public:
int result = 0;

void Push(int& x)  {
result += x;
}
int ReturnVal()
{
return result;
}
};
struct CumProd {
public:
int result = 1;

void Push(int& x)  {
result *= x;
}
int ReturnVal()
{
return result;
}
};

class Example
{
public:
const int vector_size = 10;
std::string choice;
std::vector<CumSum * if choice == "A" else CumProd *> methods;
public:
Example(std::string method)
{
choice = method;
for (size_t ii = 0; ii < vector_size; ++ii)
{
methods.push_back(choice == "A" ? new CumSum() : new CumProd());
}
}
std::vector<int> process(std::vector<float> value)
{
std::vector<int> result(value.size(), NAN);
for (size_t ii = 0; ii < value.size(); ++ii)
{
methods[ii]->Push(value[ii]);
result[ii] = methods[ii] -> ReturnVal();
}
return result;
}
};

问题是我应该如何正确地声明方法向量

std::vector<CumSum * if choice == "A" else CumProd *> methods;

非常感谢!


稍微更新了演示代码以使问题变得清楚。

在这种情况下,您可以使用多态性或std::variant来解决此问题。这将允许您在vector中存储MethodAMethodB的实例。

多态性

#include <vector>
#include <memory>
#include <iostream>
struct Base {
virtual void push(int& x) const = 0;
virtual ~Base() = default;
};
struct MethodA : public Base {
void push(int& x) const override {
x += 1;
}
};
struct MethodB : public Base {
void push(int& x) const override {
x += 20;
}
};
int main() {
std::vector<std::unique_ptr<Base>> methods{};
methods.push_back(std::make_unique<MethodA>());
methods.push_back(std::make_unique<MethodB>());
int initial = 1;
for (const auto& method : methods) {
method->push(initial);
std::cout << initial << 'n';
}
}

变体

如果您使用std::变体,请查看文档。还有其他免费函数可用于查询当前持有的类型和获取实例(如std::get(。此外,访问者模式可以用于进一步清理。

#include <vector>
#include <iostream>
#include <variant>
struct MethodA {
void push(int& x) const {
x += 1;
}
};
struct MethodB {
void push(int& x) const {
x += 20;
}
};
using MethodTypes = std::variant<MethodA, MethodB>;
int main() {
std::vector<MethodTypes> methods{};
methods.push_back(MethodA{});
methods.push_back(MethodB{});
int initial = 1;
for (const auto& method : methods) {
if (auto* a = std::get_if<MethodA>(&method)) {
a->push(initial);
std::cout << initial << 'n';
}   
else if (auto* b = std::get_if<MethodB>(&method)) {
b->push(initial);
std::cout << initial << 'n';
}      
}
}

这是C++的一个经典问题。正如一位评论者所提到的,C++是静态类型的,所以所有类型的东西都必须在编译时已知。然而,有两种典型的解决方法。

方法1:多态性

这是一个更像Java的解决方案,在运行时会稍微慢一点。我在这里使用的是std::unique_ptr类型的智能指针,因此不需要手动释放内存。

#include <memory>
#include <vector>
#include <string>
class MethodBase {
public:
virtual void push(int&) = 0;
virtual ~MethodBase() { }
};
class MethodA :public MethodBase {
public:
void push(int& X) override {
X += 1;
}
};
// similar for MethodB
void make_vector(std::string choice) {
std::vector<std::unique_ptr<MethodBase>> methods;
if (choice == "A") {
methods.push_back(std::make_unique<MethodA>());
}
else { /* ... deal with other method choices ... */ }

// now you can call anything in the MethodBase interface
int x = 100;
methods.front()->push(x);
}

方法2:模板

C++模板允许您轻松地编译多个";副本";任何功能或类别,根据需要按需提供。那么你需要一些其他地方的条件语句来决定哪个";复制";实际使用。

这种方式在运行时将比多态性稍微快一点,不使用动态内存,但它也不那么灵活,因为你没有真正得到一个可以是任何一种向量的变量。

class MethodA {
public:
void push(int& X) {
X += 1;
}
};
// similar for MethodB
template <typename C>
void make_vector() {
std::vector<C> methods;
// populate the vector
methods.emplace_back(); // constructs a new method object in-place
// now use it...
int x = 100;
methods.front().push(x);
}
int main() {
std::string choice;
std::cin >> choice;
if (choice == "A") {
make_vector<MethodA>();
}
else { /* other cases for MethodB etc */ }
}

如果您只需要一个成员函数,则可以使用std::function为您进行虚拟调度。

std::function<int(int)> methodA()
{
return [method = MethodA{}](int value) { 
method.push(value); 
return method.returnValue(); 
};
}
std::function<int(int)> methodB()
{
return [method = MethodB{}](int value) {
method.push(value); 
return method.returnValue(); 
};
}
class Example
{
public:
const int vector_size = 10;
std::vector<std::function<int(int)>> methods;
public:
Example(std::string method)
{
for (size_t ii = 0; ii < vector_size; ++ii)
{
methods.push_back(choice == "A" ? methodA() : methodB());
}
}
void process(std::vector<float> value)
{
for (size_t ii = 0; ii < value.size(); ++ii)
{
results[ii] = methods[ii](value[ii]);
}
}
};

如果您能够修改MethodAMethodB,则可以通过重命名push:来进一步简化

class Sum
{
public:
int operator()(int X)
{
result += x;
return result;
}
};
class Product
{
public:
int operator()(int X)
{
result *= x;
return result;
}
};
class Example
{
public:
const int vector_size = 10;
std::vector<std::function<int(int)>> methods;
public:
Example(std::string method)
{
for (size_t ii = 0; ii < vector_size; ++ii)
{
if (choice == "A") {
methods.push_back(MethodA{});
} else {
methods.push_back(MethodB{});
}
}
}
void process(std::vector<float> value)
{
for (size_t ii = 0; ii < value.size(); ++ii)
{
results[ii] = methods[ii](value[ii]);
}
}
};

您也可以将函数移动到Cumulative类中。

struct CumulativeOp {
int result;
std::function<int(int, int)> op;
void Push(int x)  {
result = op(result, x);
}
int ReturnVal()
{
return result;
}
};
CumulativeOp sum() {
return { 0, std::plus{} };
}
CumulativeOp prod() {
return { 1, std::times{} };
}
class Example
{
public:
const int vector_size = 10;
std::vector<CumulativeOp> methods;
public:
Example(std::string method)
: methods(vector_size, choice == "A" ? sum() : prod())
{
}
void process(std::vector<float> value)
{
for (size_t ii = 0; ii < value.size(); ++ii)
{
methods[ii].push(value[ii]);
results[ii] = methods[ii].ReturnVal();
}
}
};

顺便说一句,你不能通过传递float &来调用一个期望int &的函数,这正是process想要做的。你必须决定你有int秒还是float秒。

最新更新