What is the difference between function templates and class templates? - c++

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
}

Related

Why does automatic template deduction fail?

I've already asked a similar question here: Why does automatic type deduction fail?
However, I think I stripped down the code example too much in order to make a minimal working example. It does not reflect the problem I am facing.
Consider the code below. Why is it needed to add <int, std::string> as template arguments? Shouldn't the compiler be able to deduce this from fn_myfunc itself?
#include <functional>
#include <string>
template <class In, class Out>
class MyClass{
public:
MyClass(
std::function<Out (In)> process
) :
process_(process)
{
}
private:
std::function<Out (In)> process_;
};
std::string myfunc(int in) {
return std::to_string(in);
}
int main(int argc, char * * argv) {
std::function<std::string (int)> fn_myfunc = myfunc;
MyClass<int, std::string> instance(fn_myfunc);
return 0;
}

Using a templated function as template parameter

I'm writing a class with a function that is repeatedly called and decided to implement this as giving the function as template parameter.
As a concrete example of what I'm talking about, consider the following class:
#include <array>
template<double (*func)(std::array<double,3>)>
class MyClass
{
public:
MyClass()
{
std::array<double,3> v {{0.1,0.2,0.1}};
func(v);
}
};
which can then be instantiated with a function, as for example:
double func(std::array<double,3> x)
{
return x[0]*x[0]+x[1];
}
int main()
{
MyClass<func> entity;
}
However, I need the function to be callable with different types (the operations in the function are of course applicable to all of them), that is I want to have this function templated, as in:
template<typename scalartype, typename vectype>
scalartype func1(vectype x)
{
scalartype res = x[0]*x[0]+x[1];
return res;
}
I can still use this as template parameter, but the function parameter and return type are then fixed in the class. So how can I have the function as templated function available in the class? Such that I can, for example, call it with an std::vector of four integers and have an integer returned.
I tried using template template parameters, but I can't even figure out how to use two template parameters with them (as they only seem to allow the template ... syntax). I'm sorry if this is formulated unclearly, I am still a newcomer.
You can put your template function in a class, and then pass in that class to MyClass.
#include <iostream>
#include <vector>
#include <array>
struct templateHolder {
template <typename vectype, typename scalartype = typename vectype::value_type>
static scalartype func(vectype x) {
return x[0] + x[1];
}
};
template<typename T>
class MyClass
{
public:
MyClass()
{
std::vector<int> vec {1,2};
std::cout << T::func(vec) << std::endl;
std::array<double, 2> arr {0.5, 3.33};
std::cout << T::func(arr) << std::endl;
}
};
int main() {
MyClass<templateHolder> foo;
return 0;
}
I chose to deduce scalartype from vectype. Not necessarily what you want but it could be an option depending on your use-case.

STL container as template parameter in function, error in call

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;
}

c++ How to implement compose2

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <algorithm>
#include <ctime>
#include <iterator>
#include <string>
#include <numeric>
template <typename BinaryFunction, typename UnaryFunction1, typename UnaryFunction2>
struct compose2 {
compose2(BinaryFunction binFunc, UnaryFunction1 unFunc1, UnaryFunction2 unFunc2)
: m_binFunc(binFunc)
, m_unFunc1(unFunc1)
, m_unFunc2(unFunc2)
{}
typedef typename BinaryFunction::return_type return_type;
typedef typename UnaryFunction1::argument_type argument_type;
return_type operator()(argument_type arg) {
return m_binFunc(m_unFunc1(arg), m_unFunc2(arg));
}
BinaryFunction m_binFunc;
UnaryFunction1 m_unFunc1;
UnaryFunction2 m_unFunc2;
};
int main() {
std::vector<int> v;
v.push_back(1);
v.push_back(75);
v.push_back(10);
v.push_back(65);
v.push_back(15);
v.push_back(78);
v.push_back(14);
v.push_back(19);
int x = 10, y = 20;
std::vector<int>::iterator it = std::find_if(v.begin(), v.end(),
compose2(
std::logical_and<bool>(),
std::bind1st(std::less<int>(), x),
std::bind1st(std::greater<int>(), y)
));
std::cout << (it - v.begin()) << std::endl;
}
I have tried to implement compose2 adaptor but this doesn't compile. I am getting main.cpp:43:29: error: missing template arguments before ‘(’ token and don’t know what template arguments I should pass. Why it doesn't detect the types.
I know that this is implemented in boost or other library or in new c++11 standard. But I only want to know why does my implementation fail. Thanks.
The compiler can only deduce template arguments for function templates, not class templates. That leaves you with a few choices: the most obvious (but often least convenient) is to specify the template parameters when you instantiate your compose2.
Marginally less obvious, but often more convenient is to create a function template that deduces the parameters, and creates a compose2 object using the deduced types:
template<class BinaryFunction, class UnaryFunction1, class UnaryFunction2>
compose2<BinaryFunction, UnaryFunction1, UnaryFunction2>
make_compose2(BinaryFunction binFunc, UnaryFunction1 unFunc1, UnaryFunction2 unFunc2) {
return compose2_t<BinaryFunction, UnaryFunction2, UnaryFunction2>
(binFunc, unFunc1, unFunc2);
}
Then the client code will use make_compose2 instead of compose2, and the template parameters can/will be deduced from the types of the passed parameters.

nontype template parameter why can not pass std::vector

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);
}