Variadic Template not working expectetly

Dear Community,

i cannot figure out how to solve this. I am coding a Container Class and run into a Problem with my constructor. I wanna take a variadic list of arguments of the specified type and add them to my array like f.ex. std::vector can do, but this does not work. Why and how to fix that?

my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>

template <typename VTYPE>


class ContainerList{
    VTYPE* _data = nullptr;
    size_t size{};


public:

    VTYPE* begin() {return _data;}
    VTYPE* end() {return _data + size;}
    void push_back(VTYPE elem) {
        if (_data == nullptr)
        {
            VTYPE *_copy = new VTYPE[size = 1]{};
            _copy[size - 1] = elem;
            _data = _copy;

        } else
        {
            VTYPE *_copy = new VTYPE[++size]{};
            std::copy(_data, _data + size, _copy);
            _copy[size - 1] = elem;
            delete[] _data;
            _data = _copy;

        }
    }
    
    ContainerList() = default;



    // this part is not working
    template<typename ...VTLST>
    ContainerList(VTLST... arg) { push_back(arg...);}
    // VTLST showld only take values of type VTYPE



    VTYPE operator[](size_t ind) {return _data[ind];}
    ~ContainerList() {delete[] _data;}
};


usage:
 
ContainerList<int> hello{12, 41, 55};


[runtime does not matter]

Any advices?

nice greetings

Luke
Last edited on
it's not just "not working", it's saying exactly what's wrong:
no matching function for call to 'ContainerList<int>::push_back(int&, int&, int&)'
note: candidate: 'void ContainerList<VTYPE>::push_back(VTYPE) [with VTYPE = int]'
note:  candidate expects 1 argument, 3 provided


There are many other things to fix in this code, but the minimal fix for this error message is to re-write line 39 so it calls the 1-argument push_back 3 times, rather than non-existent 3-argument push_back 1 time
ContainerList(VTLST... arg) { (push_back(arg), ...);}
Last edited on
Thank you very much
Why not use an initializer_list?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <initializer_list>

template <typename VTYPE>
class ContainerList {
	VTYPE* _data {};
	size_t size {};

public:
	VTYPE* begin() const { return _data; }
	VTYPE* end() const { return _data + size; }

	void push_back(const VTYPE& elem) {
		if (_data == nullptr)
			_data = new VTYPE[size = 1] {elem};
		else {
			auto* _copy { new VTYPE[++size] {} };

			std::copy(_data, _data + size, _copy);
			_copy[size - 1] = elem;
			delete[] _data;
			_data = _copy;
		}
	}

	ContainerList() = default;
	ContainerList(const VTYPE& i) : size(1), _data(new VTYPE[1] {i}) {}

	ContainerList(std::initializer_list<VTYPE> il) {
		for (const auto& i : il)
			push_back(i);
	}

	VTYPE operator[](size_t ind) { return _data[ind]; }
	const VTYPE operator[](size_t ind) const {return _data[ind]; }

	~ContainerList() {
		delete[] _data;
	}

	ContainerList(const ContainerList&) = delete;
	ContainerList& operator=(const ContainerList&) = delete;
};

int main() {
	ContainerList<int> hello { 12, 41, 55 };

	for (auto i { hello.begin() }; i != hello.end(); ++i)
		std::cout << *i << "  ";

	std::cout << '\n';

	ContainerList<int> h1(34);

	std::cout << h1[0] << '\n';

	h1.push_back(99);
	h1.push_back(66);

	for (auto i { h1.begin() }; i != h1.end(); ++i)
		std::cout << *i << "  ";

	std::cout << '\n';

}

Last edited on
Hi,

To have a proper RAII class, ensure in the destructor that you delete all the things you made with new . At the moment you run the risk of memory leakage when faced with an exception.
https://en.cppreference.com/w/cpp/language/raii

Use std::size_t , not a naked size_t.

If you have begin() and end() defined, or the object is an array, and you wish to iterate the whole container, you can use a range based for loop.

Rule of 0,3,5 : https://en.cppreference.com/w/cpp/language/rule_of_three

Consider using noexcept
https://en.cppreference.com/w/cpp/language/noexcept
https://en.cppreference.com/w/cpp/language/noexcept_spec


Edit:

Oh and [[nodiscard]] (C++17) for functions that return something:
https://en.cppreference.com/w/cpp/language/attributes
Last edited on
I wanna take a variadic list of arguments of the specified type


Using templates, then consider:

1
2
3
4
5
6
7
template<typename... Ts>
using AllSame = std::enable_if_t<std::conjunction_v<std::is_same<VTYPE, Ts>...>>;

template<typename... Ts, typename = AllSame<Ts...>>
ContainerList(Ts... arg) {
	(push_back(arg), ...);
}


1
2
3
ContainerList<int> hello { 12, 76};    // OK
//ContainerList<int> hello { 12.1, 76};    // Bad
ContainerList<double> hello { 12.1, 76.0};    // OK 

Last edited on
C++20:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <concepts>

template < typename VTYPE > struct ContainerList
{
    // if: every constructor argument must be of a type convertible to VTYPE
    template < std::convertible_to<VTYPE>... T > ContainerList( T&&... args )
    { ( ( push_back( std::forward<T>(args) ) ), ... ) ; }

    // or if: every constructor argument must be of type VTYPE
    // template < std::same_as<VTYPE>... T > ContainerList( T&&... args )
    // { ( ( push_back( std::forward<T>(args) ) ), ... ) ; }

    void push_back( const VTYPE& ) { /* ... */ } // copy construct at the back
    void push_back( VTYPE&& ) { /* ... */ } // move construct at the back
    
    // ... 
};
Topic archived. No new replies allowed.