list<T> within a template ?

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
#include <iostream>
#include <list>
using namespace std;

template <typename T>
void DisplayContents(const T& inList)
{
	//list<T>::const_iterator element = inList.begin();
	//list<int>::const_iterator element = inList.begin();
	auto element = inList.begin();
	for (element; element != inList.end(); ++element)
		cout << *element << ", ";
	cout << endl << endl;
}


template <typename T, typename Type>
void DisplayContents2(const T& inlist)
{

	list<Type>::const_iterator element = inlist.begin();
	for (element; element != inlist.end(); ++element)
		cout << *element << ", ";
	cout << endl << endl;
}

int main()
{
	list <int> linkInts1;
	linkInts1.insert(linkInts1.begin(), 222);
	linkInts1.insert(linkInts1.begin(), 111);
	linkInts1.insert(linkInts1.end(), 333);

	DisplayContents(linkInts1);
	//DisplayContents<list<int>>(linkInts1);


	DisplayContents2<list<int>, int>(linkInts1);


	return 0;
}


In my first DisplayContents function:
list<T>::const_iterator element = inList.begin();

...list<T> does not have the ability to deduce the type, based upon the list<int> that is sent in. I initially thought it might be similar to how the implicit conversion happens with functions & objects (below). But it does not appear to work that way with list<T>.


1
2
3
4
5
6
7
8
9
10
11
class ClassPrime
{
public:
     ClassPrime(int intNum){}
};

void func1 (const classObject& obj1){}

int main{
func1 (10);
}



How would I get DisplayContents2 to work for list<Type>, lets say if I did not want to use auto? Thanks in advance!


> How would I get DisplayContents2 to work for list<Type>, lets say if I did not want to use auto?

C++20:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <list>
#include <ranges>

template < typename T >
concept output_streamable = requires( T&& v, std::ostream& stm ) { { stm << v } -> std::same_as<std::ostream&> ; } ;

template < std::ranges::input_range RANGE >
std::ostream& print( RANGE&& range, std::ostream& stm = std::cout ) requires output_streamable< std::ranges::range_value_t<RANGE> >
{
    for( /* auto&& */ std::ranges::range_reference_t<RANGE> v : range ) stm << v << ' ' ;
    return stm << '\n' ;
}

int main()
{
    const std::list lst { 111, 333, 222, 555 } ;
    print(lst) ;

    const double arr[] { 1.2, 3.4, 5.6, 7.8, 9.1 } ;
    print(arr) ;
}

http://coliru.stacked-crooked.com/a/209cc483b2a42ae1
C++11:
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
#include <iostream>
#include <list>
#include <vector>

template < typename CNTR >
std::ostream& print( const CNTR& cntr, std::ostream& stm = std::cout )
{
    for( /* const auto& */ const typename CNTR::value_type& v : cntr ) stm << v << ' ' ;
    return stm << '\n' ;
}

template < typename T, typename A, template<typename,typename> class CNTR >
std::ostream& print2( const CNTR<T,A>& cntr, std::ostream& stm = std::cout )
{
    for( /* const auto& */ const T& v : cntr ) stm << v << ' ' ;
    return stm << '\n' ;
}

int main()
{
    const std::list<int> lst { 111, 333, 222, 555 } ;
    print(lst) ;
    print2(lst) ;

    const std::vector<double> vec { 1.2, 3.4, 5.6, 7.8, 9.1 } ;
    print(vec) ;
    print2(vec) ;
}

http://coliru.stacked-crooked.com/a/c76681335438c708
Actually T is already the type of the list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template <typename T>
void DisplayContents2(const T& inlist)
{

	typename T::const_iterator element = inlist.begin();
	for (element; element != inlist.end(); ++element)
		cout << *element << ", ";
	cout << endl << endl;
}


int main()
{
	list <int> linkInts1;

...

	DisplayContents2(linkInts1);


	return 0;
}
1) Works out nicely then when you can use it like a typedef, but have to place typename in front. Thanks!


2) I have not seen C++20 concept/requires yet and I saw you also used it on your previous post of mine. I already acquired my C++20 book, but need more time before diving in.


3) I saw operator << that takes in ostream& and returns the stream to the cout in the main(). But it is trippy that you can set the stream = std::cout and have it return the stream and it just print it.


4) I know what the rest does, but still trying to figure out what....
...", typename A, template<typename,typename> class CNTR >" does with this
"( const CNTR<T,A>& cntr,..."

A) typename T (gets either "list<int>" or "vector<double>")
B) typename A (What does that get?????)
C) const CNTR<T,A>& cntr (that calls the 2nd template....template<T,A> class CNTR....??)
The http://www.cplusplus.com/reference/list/list/ starts with:
template < class T, class Alloc = allocator<T> > class list;

Note that template for std::list has two typenames: "T" and "Alloc". So does std::vector. We hardly ever notice that, because there is a default for Alloc.
> I know what the rest does, but still trying to figure out what....
> ...", typename A, template<typename,typename> class CNTR >" does with this
> "( const CNTR<T,A>& cntr,..."


CNTR is a template template parameter - for a template class having two template type parameters

A) typename T : the type of the element in the container. ( int in "list<int>" or double in "vector<double>"

B) typename A : the allocator used by the container (the default allocator is used in our examples)
https://en.cppreference.com/w/cpp/memory/allocator
The allocator is used by the container to acquire/release memory and to construct/destroy the elements in that memory. For example, see the second template parameter of std::vector https://en.cppreference.com/w/cpp/container/vector

C) const CNTR<T,A>& cntr : The template class taking two template arguments
In our example, std::list< int, std::allocator<int> > or std::vector< double, std::allocator<double> >
Last edited on
Registered users can post here. Sign in or register to post.