Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store parameters from variadic template member function into vector?

Tags:

c++

#include <Windows.h>
#include <string>
#include <vector>
#include <iostream>
using namespace std;

class CTest
{
public:
    template<typename... Args>
    void AddStringsToVector(const std::string &First, Args&... args);
private:
    std::vector<std::string> m_stringsvec;
};

template<typename... Args>
void CTest::AddStringsToVector(const std::string &First, Args&... args)
{
    m_stringsvec.push_back(First);
    m_stringsvec.push_back(args...);

    for (auto &i : m_stringsvec)
        std::cout << i << std::endl;
}

void main()
{
    CTest test;
    test.AddStringsToVector("test1","test2","test3");
    system("pause");
}

only works when i pass two parameters:

test.AddStringsToVector("test1","test2");

If I pass any number of parameters other then two I get an error.

For example:

test.AddStringsToVector("test1","test2","test3");

Error: Severity Code Description Project File Line Error C2661 'std::vector>::push_back': no overloaded function takes 2 arguments

like image 390
xxX360noscopePROXX Avatar asked Dec 29 '15 06:12

xxX360noscopePROXX


3 Answers

Recursively call the function .

void CTest::AddStringsToVector()//function to break recursion 
{

}
template<typename... Args>
void CTest::AddStringsToVector(const std::string &First, Args&... args)
{
    m_stringsvec.push_back(First);
    AddStringsToVector(args...);


}
like image 97
SACHIN GOYAL Avatar answered Oct 02 '22 00:10

SACHIN GOYAL


A non-recursive method:

class CTest
{
public:
    template<typename... Args>
    void AddStringsToVector(const std::string &first, const Args&... args)
    {
        m_stringsvec.push_back(First);
        int dummy[] = { 0, (m_stringsvec.push_back(args), 0)...}; // all magic is here
        (void) dummy; // Avoid unused variable warning.

        for (const auto &s : m_stringsvec) {
            std::cout << i << std::endl;
        }
    }
private:
    std::vector<std::string> m_stringsvec;
};

The real stuff is there:

int dummy[] = { 0, (m_stringsvec.push_back(args), 0)...};

(foo(), 0) uses comma operator. That do the first part (the job we want) and evaluate as 0.

With variadic expansion, it becomes (m_stringsvec.push_back(args), 0)....

put the whole in initializer list to guaranty order evaluation.

In C++17, it would be even simpler with folding expression:

    template<typename... Args>
    void AddStringsToVector(const std::string &first, const Args&... args)
    {
        m_stringsvec.push_back(First);
         (m_stringsvec.push_back(args), ...); // Folding expression

        for (const auto &s : m_stringsvec) {
            std::cout << i << std::endl;
        }
    }
like image 22
Jarod42 Avatar answered Oct 02 '22 00:10

Jarod42


Another non-recursive option (warning, brain compile):

struct swallow { template <typename ...T> swallow(T&& ...) noexcept { } };

class CTest
{
public:
    template<typename... Args>
    void AddStringsToVector(const std::string &first, const Args&... args)
    {
        m_stringsvec.push_back(First);
        swallow{(m_stringsvec.push_back(args), 0)...};

        for (const auto &s : m_stringsvec) {
            std::cout << i << std::endl;
        }
    }
private:
    std::vector<std::string> m_stringsvec;
};
like image 45
user1095108 Avatar answered Oct 02 '22 00:10

user1095108