Here I want to simplify my c code from version 2 to version 1. In a language like Python, it's simple to refer to a different types of variables like version 1. How can I achieve similar code in c ?
#include <iostream>
#include <vector>
/* version 1: compile failed */
void display(std::vector<int> vi, std::vector<double> vd) {
// error: operands to ?: have different types
// ‘std::vector<double>’ and ‘std::vector<int>’
auto& v = vi.empty() ? vd : vi;
for (const auto &e : v) {
std::cout << e << " ";
}
}
/* version 2 */
void display(std::vector<int> vi, std::vector<double> vd) {
if (!vi.empty()) {
for (const auto &e : vi) {
std::cout << e << " ";
}
} else {
for (const auto &e : vd) {
std::cout << e << " ";
}
}
}
int main(int argc, char *argv[]) {
std::vector<int> vi{0, 1, 2};
std::vector<double> vd{10., 11, 12};
// one of vi, vd can be empty after some modifications
...
display(vi, vd);
return 0;
}
Supplement:
Here the print function is only an example. My main purpose is to create a reference to std::vector<int>
or std::vector<double>
according to whether they are empty or not. The following example may
#include <iostream>
#include <vector>
void process_1(std::vector<int> v) {
for (const auto &e : v) {
std::cout << e << " ";
}
std::cout << std::endl;
}
void process_1(std::vector<double> v) {
double sum = 0;
for (const auto &e : v) {
sum = e;
}
std::cout << sum << std::endl;
}
void process_2(std::vector<int>) {
//...
}
void process_2(std::vector<double>) {
//...
}
/* Version 2 */
int version_2(int argc, char *argv[]) {
std::vector<int> vi{0, 1, 2};
std::vector<double> vd{10., 11, 12};
if (!vi.empty()) {
process_1(vi);
} else {
process_1(vd);
}
// do something
if (!vi.empty()) {
process_2(vi);
} else {
process_2(vd);
}
return 0;
}
/* Version 1 */
int version_1(int argc, char *argv[]) {
std::vector<int> vi{0, 1, 2};
std::vector<double> vd{10., 11, 12};
// in Python, it's easy to create a reference dynamically, eg:
// ref = vd is len(vi) == 0 else vi
auto &ref = vd if vi.empty() else vi;
process_1(ref);
// do something
process_2(ref);
return 0;
}
CodePudding user response:
Something along these lines, perhaps:
void display(const std::vector<int>& vi, const std::vector<double>& vd) {
auto print_sequence = [](const auto& v) {
for (const auto &e : v) {
std::cout << e << " ";
}
}
vi.empty() ? print_sequence(vd) : print_sequence(vi);
}
CodePudding user response:
What you're searching for is a visitor.
First version:
void display(std::vector<int> vi, std::vector<double> vd) {
auto vis = [](const auto& v) {
for (const auto& e : v) {
std::cout << e << " ";
}
};
if (vi.empty()) {
vis(vd);
} else {
vis(vi);
}
}
Note however, you don't necessarily need to pass two arguments, you might use a std::variant<std::vector<int>, std::vector<double>>
:
void display(std::variant<std::vector<int>, std::vector< double>> vv) {
auto vis = [](const auto& v) {
for (const auto& e : v) {
std::cout << e << " ";
}
};
std::visit(vis, vv);
}
As a variant is constructible from any of the types, you can simply pass it either vi
or vd
.
This works with arbitrary number of types.
Also, suggest passing arguments by const
reference (e.g., const std::variant<std::vector< int>, std::vector< double>>&
).