Home > Net >  How to pass only selected arguments to a function?
How to pass only selected arguments to a function?

Time:09-13

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"};

Demo

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");
  • Related