我需要在 A、B、C 类 上测试 a()、b()、c()。最简单的使用方法是要求 3*3 if-else。我想试试 3+3 if-else.
Class A
{
...
public:
int k(){...};
...
};
Class B
{
...
public:
int k(){...};
...
};
Class C
{
...
public:
int k(){...};
...
};
template<class T>
void a(const T& g, int m)
{
...
g.k();
...
}
template<class T>
void b(const T& g, int m, int n)
{
...
g.k();
...
}
template<class T>
void c(const T& g, int m, int n, int o)
{
...
g.k();
...
}
然后看到variant,用它来实现3+3 if-else
int main(int argc, char** argv)
{
std::variant<std::monostate, A, B, C> x;//For some reason A, B, C do not have the default constructors
if(argv[1]=="A") x=A(...);
else if(argv[1]=="B") x=B(...);
else if(argv[1]=="C") x=C(...);
//error 1 How to use a function that takes more than two arguments directly here?
if(argv[2]=="a") std::visit(a, x, atoi(argv[2]));
else if if(argv[2]=="b") std::visit(b, x, atoi(argv[2]), atoi(argv[3]));
else if(argv[2]=="c") std::visit(c, x, atoi(argv[2]), atoi(argb[3]), atoi(argv[4]));
//error 2 Since A, B, C do not have the default constructors, monostate does not have the k() required by a(), b(), c().
if(argv[2]=="a") std::visit([&](const auto& G){a(G, atoi(argv[2]));}, x);
else if if(argv[2]=="b") ...;
else if(argv[2]=="c") ...;
}
请找到更好的方法或解决上面的error1和error2,非常感谢。
但无论如何,我实际上是想看看是否有更好的方法来编写它来避免 3*3 if-else。
//i want to avoid
int main(int argc, char** argv)
{
if(argv[1]=="A")
{
A tmp_class;
if(argv[2]=="a") a(tmp_class);
else if(argv[2]=="b") b(tmp_class);
else c(tmp_class);
}
else if(argv[1]=="B")
{
B tmp_class;
if(argv[2]=="a") a(tmp_class);
else if(argv[2]=="b") b(tmp_class);
else c(tmp_class);
}
else
{
C tmp_class;
if(argv[2]=="a") a(tmp_class);
else if(argv[2]=="b") b(tmp_class);
else c(tmp_class);
}
}
是否有更好的方法达到 3+3 if-else?
//pseudocode
int main(int argc, char** argv)
{
T tmp_class;
//3 if-else
if(argv[1]=="A") tmp_class=A(...);
else if(argv[1]=="B") tmp_class=B(...);
else tmp_class=C(...);
//+
//3 if-else
if(argv[2]=="a") a(tmp_class);
else if(argv[2]=="b") b(tmp_class);
else c(tmp_class);
}
使用
std::visit
的最干净的方法是创建一个 overloaded
struct
派生自您创建的每个 lambda
以处理您的 std::variant
在任何给定时间可能持有的所有潜在类型。
在我展示的示例中,我没有定义任何构造函数,所以
std::monostate
不是明确需要的,但我还是添加了它以向您展示如何处理 std::variant
没有被赋值的情况;
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// Deduction guide is only needed pre C++20.
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
struct A {
void print(const std::string_view msg) const {
std::cout << msg << '\n';
}
};
struct B {};
struct C {};
using types = std::variant<std::monostate, A, B, C>;
int main()
{
// You can either assign an already created object to the variant.
types values = B{};
// Or you can create the object in place.
values.emplace<A>(/* Here you can pass constructor arguments if required. */);
const std::string_view msg{ "'A' class" };
std::visit(overloaded {
// Note that I'm capturing the variable 'msg' and using it in the lambda.
[&msg](const A& a) { a.print(msg); },
[](const B& b) { std::cout << "B\n"; },
[](const C& c) { std::cout << "C\n"; },
[](std::monostate) { std::cout << "Nothing\n"; }
}, values);
// Note that you can also use the following free functions
// to check/get the object of a specific type from the variant.
if (std::holds_alternative<A>(values)) {
// Holds 'A' so lets use std::get to get a reference to the object.
const A& a{ std::get<A>(values) };
}
if (const auto* ptr{ std::get_if<B>(&values) }) {
// Holds 'B'.
}
}