c++arguments

how could I pass variable arguments and use them one by one in a loop


Here is a rudent prototype that I want to implement:

void save_keys(const string& savepth, const vector<string>& keys) {

    size_t n_samples = keys.size();
    stringstream ss;
    for (size_t i{0}; i < n_samples - 1; ++i) {
        ss << keys[i] << endl;
    }
    ss << keys[n_samples - 1];

    ss.clear(); ss.seekg(0, ios::beg);
    ofstream fout(savepth, ios::out);
    ss >> fout.rdbuf(); fout.close();
}

void save_keys_values(const string& savepth, const vector<string>& keys, const vecotr<int>& values) {

    size_t n_samples = keys.size();
    stringstream ss;
    for (size_t i{0}; i < n_samples - 1; ++i) {
        ss << keys[i] << "," << values[i] << endl;
    }
    ss << keys[n_samples - 1] << "," << values[i];

    ss.clear(); ss.seekg(0, ios::beg);
    ofstream fout(savepth, ios::out);
    ss >> fout.rdbuf(); fout.close();
}

We can see that the two function has very similar structure and logic, only difference is that: for save_keys(...), the stringstream works in this way: ss << keys[i], but for save_keys_values(...), the stringstream works in this way: ss << keys[i] << "," << values[i].

Is there a method that I can fuse the above two implementation together, so that I can write one function(such as save_func) and call it in different conditions leading to different behavior? Such as save_func(keys) and save_func(keys, values).

Edit 1: I can use -std=c++17 when I compile my code.


Solution

  • Variadic template might help:

    template <typename... Ts>
    void save_keys_values(const std::string& savepth,
                          const std::vector<std::string>& keys,
                          const std::vector<Ts>&... values)
    {
        if (((keys.size() != values.size()) || ...))
            return;
        size_t n_samples = keys.size();
        std::stringstream ss;
        const char* sep = "";
        for (size_t i{0}; i < n_samples; ++i) {
            ss << sep << keys[i];
            ((ss << ", " << values[i]), ...);
            sep = "\n";
        }
    
        ss.clear(); ss.seekg(0, ios::beg);
        ofstream fout(savepth, ios::out);
        ss >> fout.rdbuf(); fout.close();
    }
    

    Demo