I plan to write a function which can print all the data of any container. In other words, I can use with different containers type like vector, deque or list and that I can call it with different data types ( integers , double or string).
The template function can pass the compiler, but I do not know how to call it.
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include <list>
using namespace std;
template <typename C, template <typename C> class M>
void print(M<C> data){
typename M<C>::iterator it;
for(it=data.template begin();it!=data.template end();++it){
cout<<*it<<" ";
}
cout<<endl;
}
int main(int argc, char** argv) {
list<int> data;
for(int i=0;i<4;i++){
data.push_back(i);
}
print<int>(data); //compile error
print<int, list>(data); //compile error
return 0;
}
error message:
main.cpp:35:20: error: no matching function for call to 'print(std::list&)'
main.cpp:35:20: note: candidate is:
main.cpp:21:6: note: template class M> void print(M)
some related threads:
template function for multiple containers and data types
http://louisdx.github.io/cxx-prettyprint/
As noted in the comments, std::list actually has more than one template parameter (the second parameter is the allocator). Moreover, there is no need for print to take two template parameters; you can simply parameterize it over the overall container type:
#include <iostream>
#include <iterator>
#include <list>
using namespace std;
template <typename C>
void print(const C &data){
for(auto it=begin(data);it!=end(data);++it){
cout<<*it<<" ";
}
cout<<endl;
}
int main(int argc, char** argv) {
list<int> data;
for(int i=0;i<4;i++){
data.push_back(i);
}
print(data);
return 0;
}
Demo.
As pointed out in the other answer, if you can use C++11 features, a range-for loop is better than the explicit iterator use above. If you can't (which means no auto or std::begin or std::end either), then:
template <typename C>
void print(const C &data){
for(typename C::const_iterator it=data.begin();it!= data.end();++it){
cout<<*it<<" ";
}
cout<<endl;
}
Note that since we take data by const reference, we need to use const_iterator.
Using c++11 you can simplify it to:
template <typename C>
void print(const C &data){
for (auto &elem : data)
cout << elem << " ";
cout << endl;
}
and call it with print(data). You could also use std::for_each or copy it directly into cout.
Related
I want to call a function which can accept a vector but i want to pass different type of vector to that function.
I have come across a function call like
print<int>(int_vector);
print<string>(string_vector);
here <int> and <string> are mention as what.
One more doubt is if i pass different type of vector also how can i take it in the function call. should i use void * ? then type cast it
Sample of func template
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
void foo(std::vector<T> vec)
{
// do stuff with vector
}
int main() {
std::vector<int> iv = {42};
foo(iv);
std::vector<string> sv = {"hello"};
foo(sv);
return 0;
}
There is an alternative if you know the exact types:
void foo(std::vector<int> v)
{}
void foo(std::vector<string> v)
{}
This is plain function overloading.
What you want to use here is a templated function. Simples example relevant to your question would be:
// This line says that the function accepts one generic type
// which you will refer to as T
template <typename T>
// vector<T> means that the referenced type T will be of the type the vector,
// you call this function with, is templated with
void print(const std::vector<T>& data) {
// Here calling the operator[] will return the generic type T
const T& element = data[0];
for (unsigned i = 0; i < data.size(); ++i)
std::cout << data[i] << std::endl;
}
This function would be used like this:
std::vector<int> vec = { 1, 2, 3 };
print(vec);
// Note that you don't need to write the template type here
// because it is deduced from the type of vector
And the output will be:
1
2
3
The code is using template programming to make a generic function:
template <typename T>
void foo(T item){
// do something to item of type T
}
void foo(int str); // Declare a certain type of template
Later you can use the function:
int x = 1;
foo<int>(x);
But in this case, because e.g. printf uses different formatting for different types, it might be wise to instead overload the functions. Overloading is the practise of naming functions similarly, but giving different arguments:
void foo(std::vector<int> v);
void foo(std::vector<string> v);
This concept is known as generic programming. In C++, you use templates to achieve this, and specifically a function template. If you want different types of lists with different types to be auto-deduced, or have a specific need for advanced templates, you can also use a template-template.
An example:
#include <iostream>
#include <vector>
#include <list>
template < template < class, class > class V, class T, class A >
void erase_value(V<T, A>& v, const T& t)
{
typename V<T,A>::iterator s = v.begin();
while (s != v.end()) {
if ((*s) == t) { v.erase(s); break; }
++s;
}
}
template < typename T >
void print_all(T begin, T end)
{
for (; begin != end; ++begin) {
std::cout << *begin << " ";
}
std::cout << std::endl;
}
template < typename T >
void print_all(const T& array)
{
for (auto i : array) {
std::cout << i << " ";
}
std::cout << std::endl;
}
int main(int argc, char** argv)
{
std::vector<std::string> strings {"123","321","ABC"};
std::list<int> ints {123,321,5332};
print_all(strings);
print_all(ints);
erase_value(strings, std::string("123"));
erase_value(ints, 123);
print_all(strings.begin(), strings.end());
print_all(ints.begin(), ints.end());
return 0;
}
Hope that can help.
I believe you're looking for ostream_iterator:
template <typename T>
void print(vector<T> arg){
copy(cbegin(arg), cend(arg), ostream_iterator<T>(cout, " "));
}
Cant understand what is wrogn with code, second function definition or call of this function in main?
I think, but not sure, problem in call, cause without calling code compiles well. Compiler gcc
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void show_element(T ob)
{
cout << ob << " ";
}
template<template<class> class S, class T>
void show_sequence(S<T> sequence)
{
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
int main(int argc, char const *argv[])
{
std::vector<int> v(20, 0);
//here the problem
show_sequence<std::vector<int>, int>(v);
return 0;
}
std::vector isn't a template of one parameter, it takes an allocator type as well. You can use it as vector<T> simply because the second parameter has a default (std::allocator<T>).
As it's written, your template function cannot accept any standard container, since off the top of my head, none take just a single type parameter.
An approach that would work, and not require you to know how many template parameters a container requires, is to accept a container type (not template), and glean the value type from the container type.
template<class Seq>
void show_sequence(Seq const& sequence)
{
typedef typename Seq::value_type T;
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
All standard containers have a value_type member, so this will work with any of them. Furthermore, it will work with any container that takes its cue from the standard library.
The problem is that std::vector is a template but std::vector<int> is a type.
When you are giving the second one to the function, you are giving one type and not a template.
So, you can rewrite your function as :
template<class S>
void show_sequence(S sequence)
Moreover, vector does not take only one template paramete but two (see StoryTeller answer)
It is similar to this question: https://stackoverflow.com/a/29493191/1889040
It is because vector is template of <type, allocator>
The code should be
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void show_element(T ob)
{
cout << ob << " ";
}
template<template<class,class> class S, class T, class Allocator>
void show_sequence(S<T, Allocator> sequence)
{
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
int main(int argc, char const *argv[])
{
std::vector<int> v(20, 0);
//here problem solved
show_sequence<vector, int, allocator<int> > (v);
show_sequence(v);
return 0;
}
I'm trying to pass an iterator as a template parameter to a template method, but the compiler complains that:
error C2783: 'void Test::Assert(std::vector<T>::const_iterator)':
could not deduce template argument for 'T'
The code that produces the error is:
#include "stdafx.h"
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
std::vector<double> myVec;
test.Assert(myVec.cbegin());
return 0;
}
I'm guessing there is a simple way to make this work, since most of the std algorithms can deduce type from iterator.
The reason is that the form you have T in is a non-deduced context:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
Consider a simpler case to understand why:
struct A { using type = int; };
struct B { using type = int; };
struct C { using type = int; };
template <typename T>
void Assert(typename T::type it) { ... }
Assert(5);
What should T deduce as? It's impossible to determine. You'd have to explicitly provide the type... as something like Assert<A>(5).
See also What is a nondeduced context?
since most of the std algorithms can deduce type from iterator.
That's because the standard algorithms just deduce the iterator type, not the container type. For instance std::find is just:
template <class InputIt, class T>
InputIt find( InputIt first, InputIt last, const T& value );
There is no concept of "container" here at all - it's just the iterator type that needs to be deduced. That's part of the beauty of the algorithms library.
So if what you want to do is just output the contents of the iterator, the correct function would just be:
template <typename Iterator>
void Assert(Iterator it)
{
std::cout << *it << std::endl;
}
When you call Assert(myVec.cbegin()), Iterator will get deduced as std::vector<double>::const_iterator, which is exactly what you want.
The standard algorithms look like this:
template <typename Iterator>
void some_algorithm(Iterator first, Iterator last) {
// do stuff
}
If they need the type of the iterator, they can use typename std::iterator_traits<Iterator>::value_type.
What they don't do is reference a container such as vector in any way. Not all iterators come from containers.
template <typename Ite>
void Assert(Ite &&it)
{
std::cout << *std::forward<It>(it) << std::endl;
}
That's it - the standard library just parameterizes on the whole type of the iterator. In fact, anything that behaves like an iterator can be used (that's the main reason why iterators behave like pointers). This is called "duck typing".
What you are trying to do (restricting the function to only those types which are explicit iterators) is what C++17 concepts are about.
#include "stdafx.h"
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename T::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
std::vector<double> myVec;
test.Assert<std::vector<double> >(myVec.cbegin());
return 0;
}
Try out this once.
The following code is compiled ok using clang.
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int main(int argc, char* argv[])
{
Test test;
std::vector<double> myVec;
myVec.push_back(2.0f);
test.Assert<double>(myVec.cbegin()); // call Assert in this way.
return 0;
}
The outputs:
$ ./a.out
2
The compiler's version:
$ clang++ -v
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM
3.6.0svn) Target: x86_64-apple-darwin14.1.0 Thread model: posix
I am trying with the following code.
#include <iostream>
#include <vector>
using namespace std;
template <typename T, std::vector <T> myV>
int fun()
{
cout <<" Inside fun () "<<endl;
}
int main( int argc, char ** argv)
{
std::vector<int> a;
fun<int,a>();
}
I can not pass std::vector myV ?
But instead of std::vector , i could able to use something like template
**, and fun().
What goes in triangular brackets must be a type or a compile-time constant; it cannot be a variable. Although a's type is vector<int>, a itself is an object of type vector<int>; it cannot go in triangular brackets as one of template parameters.
In addition, you cannot use vector<T> as a second type parameter of your template function: vector<T> is a type which becomes fully known once you know T. Since you already have T as your template parameter, you can declare vector<T> "for free" inside your function without an additional template parameter.
Finally, in C++11 you can get a type of a variable statically using decltype. For example, if you modify your code to take a single type parameter of T, you could do this:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
int fun()
{
cout <<" Inside fun () "<<endl;
}
int main( int argc, char ** argv)
{
std::vector<int> a;
// This is the same as calling fun<std::vector<int> >();
fun<decltype(a)>();
return 0;
}
Demo on ideone.
You need to call
fun<int, std::vector<int>>();
which passes the type std::vector<int>. If you want to pass an instance (a) of std::vector<int>, you will have to change your function definition to:
template<typename T>
int fun(std::vector<T> v)
{
std::cout << "Inside fun()\n";
}
int main()
{
std::vector<int> a;
fun(a);
}
I am confused about the strange syntax provided by C++ function templates and class templates. Take a quick look at the code below:
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>
#include <vector>
using namespace std;
template <class op1,class op2>
class compose_fg_x_t : public unary_function<typename op2::argument_type,typename op1::result_type>{
public:
// constructor
compose_fg_x_t(const op1& arg1,const op2& arg2): p1(arg1),p2(arg2){
}
//function call
typename op1::result_type operator()(const typename op2::argument_type& x) const{
return p1(p2(x));
}
private:
op1 p1;
op2 p2;
};
template <class Op1,class Op2>
inline compose_fg_x_t<Op1,Op2> compose_fg_x(const Op1& p1,const Op2& p2){
return compose_fg_x_t<Op1,Op2>(p1,p2);
}
int main(int argc, char *argv[])
{
int a[] = {1,2,3,4,5};
vector<int> IntVec(a,a+sizeof(a)/sizeof(int));
copy(IntVec.begin(),IntVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
transform(IntVec.begin(),IntVec.end(),ostream_iterator<int>(cout," "),compose_fg_x( bind2nd(multiplies<int>(),5),bind2nd(plus<int>(),10) ));
transform(IntVec.begin(),IntVec.end(),ostream_iterator<int>(cout," "),compose_fg_x_t( bind2nd(multiplies<int>(),5),bind2nd(plus<int>(),10) ));
return 0;
}
So, my question is, why is the first transform is correct while the second is not? What the helper function compose_fg_x does is return an object of the underlying compose_fg_x_t type. I am trying to omit the indirect function call, which fails to compile. Why?
Template arguments can only be deduced for function templates, not for class templates. The whole point of helper functions such as make_pair (or your compose_fg_x) is to circumvent this limitation.
Here is a slightly less complicated example that demonstrates the problem:
#include <utility>
int main()
{
auto x = std::make_pair(3, 4); // function template arguments are deduced
auto y = std::pair(3, 4); // error: missing class template arguments
}