Let's suppose I have a struct X and I want to fill out all fields depending on some conditions. I'd like to distinguish which parameter I want to pass to a function and based on provided parameters create and then return that object. I'm curious if I should use variadic templates in c ? Pseudo code.
#include <iostream>
using namespace std;
struct X
{
string a;
string b;
string c;
}
X generateTransaction(const string& e, const string& f, const string& g)
{
X one;
if (e)
one.a = e;
if (f)
one.b = f;
if (g)
one.c = g;
return one;
}
int main()
{
generateTransaction(e = "first");
generateTransaction(e = "abc", f = "second");
generateTransaction(g = "third");
generateTransaction(e = "test", g = "third");
generateTransaction("m", "n", "o");
return 0;
}
CodePudding user response:
With C 20, you might use designated initializers:
X x1{.a = "first"};
X x2{.a = "abc", .b = "second"};
X x3{.c = "third"};
X x4{.a = "test", .c = "third"};
X x5{"m", "n", "o"};
CodePudding user response:
You can pass parameters as std::optional
and then check if it has value
. Something like:
X generateTransaction(const std::optional<std::string> &e,
const std::optional<std::string> &f,
const std::optional<std::string> &g)
{
X one;
if (e.has_value())
{
one.a = e.value();
}
if (f.has_value())
{
one.b = f.value();
}
if (g.has_value())
{
one.c = g.value();
}
return one;
}
int main()
{
generateTransaction("first", {}, {});
generateTransaction("abc", "second", {});
generateTransaction({}, {}, "third");
generateTransaction("test", {}, "third");
generateTransaction("m", "n", "o");
return 0;
}
CodePudding user response:
Use a constructor to initialize members:
struct X
{
std::string a;
std::string b;
std::string c;
X(const std::string& a, const std::string& b, const std::string& c) : a(a),b(b),c(c) {}
};
Main then is:
X a("first","","");
X b("abc","second");
X c("","","third");
X d("test","","third");
X e("m", "n", "o");
You can use default arguments and for the combinations that cannot be covered with default arguments you can use static member functions (there are only 4 combinations not covered, so it is not too much boilerplate):
struct X
{
std::string a;
std::string b;
std::string c;
X(const std::string& a = "", const std::string& b = "", const std::string& c = "") : a(a),b(b),c(c) {}
static X from_ac(const std::string& a,const std::string& c) {
return {a,"",c};
}
static X from_c(const std::string& c) {
return {"","",c};
}
static X from_b(const std::string& b) {
return {"",b,""};
}
static X from_bc(const std::string& b,const std::string& c) {
return {"",b,c};
}
};
Alternatively, use std::optional
arguments, so the constructor can be called by leaving out parameters at any position:
struct X
{
std::string a;
std::string b;
std::string c;
X(const std::optional<std::string>& a, const std::optional<std::string>& b, const std::optional<std::string>& c) : a(a.value_or("")),b(b.value_or("")),c(c.value_or("")) {}
};
Main is then:
X a("first",std::nullopt,std::nullopt);
X b("abc","second",std::nullopt);
X c(std::nullopt,std::nullopt,"third");
X d("test",std::nullopt,"third");
X e("m", "n", "o");