Say I want a C++ function to perform arithmetic on two inputs, treating them as a given type:
pseudo:
function(var X,var Y,function OP)
{
if(something)
return OP<int>(X,Y);
else if(something else)
return OP<double>(X,Y);
else
return OP<string>(X,Y);
}
functions that fit OP might be like:
template <class T> add(var X,var Y)
{
return (T)X + (T)Y; //X, Y are of a type with overloaded operators
}
So, the question is what would the signature for function look like? If the operator functions are non-templated I can do it, but I get confused with this extra complexity.
Template functions cannot be passed as template arguments. You have to manually deduce template arguments for this function before you pass it to another template function. For example, you have function
T sum(T a, T b)
{
return a + b;
}
You want to pass it to callFunc:
template<typename F, typename T>
T callFunc(T a, T b, F f)
{
return f(a, b);
}
You can't simply write
int a = callFunc(1, 2, sum);
You have to write
int a = callFunc(1, 2, sum<int>);
To be able to pass sum without writing int, you have to write a functor - struct or class with operator() that will call your template function. Then you can pass this functor as template argument. Here is an example.
template<class T>
T sum(T a, T b)
{
return a + b;
}
template<class T>
struct Summator
{
T operator()(T a, T b)
{
return sum<T>(a, b);
}
};
template<template<typename> class TFunctor, class T>
T doSomething(T a, T b)
{
return TFunctor<T>()(a, b);
//Equivalent to this:
//TFunctor<T> functor;
//return functor(a, b);
}
int main()
{
int n1 = 1;
int n2 = 2;
int n3 = doSomething<Summator>(n1, n2); //n3 == 3
return 0;
}
Are you looking for this?
template<class T> T add(T X, T Y)
{
return X + Y;
}
Or are you looking for something that calls something like add?
template<class T, class F>
T Apply(T x, T y, F f)
{
return f( x, y );
}
Called via:
int x = Apply( 2, 4, add<int> );
I'm a bit confused … why the type differentiation in your pseudo-code?
C++ templates allow full type deduction on templates:
template <typename T, typename F>
T function(T x, T y, F op) {
return op(x, y);
}
Here, F fits anything (especially functions) that may be called with the () function call syntax and accepting exactly two arguments of type T (or implicitly convertible to it).
I use lambdas for this.
auto add = [](const auto& lhs, const auto& rhs) {
static_assert(std::is_arithmetic<typename std::decay<decltype(lhs)>::type>::value,
"Needs to be arithmetic.");
static_assert(std::is_arithmetic<typename std::decay<decltype(rhs)>::type>::value,
"Needs to be arithmetic.");
return lhs + rhs;
};
template<typename LHS, typename RHS, typename FUNC
, typename OUT = typename std::result_of<FUNC(LHS, RHS)>::type>
constexpr OUT do_arithmetic(LHS lhs, RHS rhs, FUNC func) {
return func(lhs, rhs);
}
constexpr auto t = do_arithmetic(40, 2, add);
static_assert(t == 42, "Wrong answer!");
static_assert(std::is_same<std::decay<decltype(t)>::type, int>::value,
"Should be int.");
template <class OP> void function(OP op)
{
// call with int
op(1, 2);
// or with double
op(1.2, 2.3);
// call with explicit template argument
op.template operator()<int>(1, 2);
op.template operator()<string>("one", "two");
}
struct Add
{
template <class T> T operator ()(T a, T b)
{
return a + b;
}
};
function(Add());
// or call with C++14 lambda
function([](auto a, auto b) { return a + b; });
I think you're looking for the Strategy Pattern.
I'm not sure what this var thing in your question means. It's certainly not a valid C++ keyword, so I assume it's a type akin to boost:any. Also, the function is missing a result type. I added another var, whatever that might be. The your solution could look like this:
template< template<typename> class Func >
var function(var X, var Y, Func OP)
{
if(something)
return OP<int>(X,Y);
else if(something else)
return OP<double>(X,Y);
else
return OP<string>(X,Y);
}
The funny template argument is a template itself, hence its name "template template argument". You pass in the name of a template, not an instance. That is, you pass std::plus, not std::plus<int>:
return function( a, b, std::plus );
Related
I have function templates :
template<typename T>
inline T fun3(T &x1, T &x2)
{
return std::pow(x1,2.0) + std::pow(x2,2.0);
}
template<typename T, typename U>
inline T fun5(U &a)
{
return (T(4.0+a*(-2.0),5.0+ a*3.0));
}
template<typename F, typename T>
void min(F fun1, T& v)
{
double x={10.0};
v=fun1(x);
}
int main()
{
double val;
min(fun3(fun5),val);
std::cout<<"value = "<<val<<"\n";
return 0;
}
I want to evaluate fun3(fun5(x)) and have functions as shown above. But getting error as no matching function for call to ‘Function5<double>::fun5(<unresolved overloaded function type>)’ obj1(o5.fun5(o3.fun3),-2.0,0.0,location,value);
Can someone explain how can I pass function to min()?
What will change if all these functions were class templates like:
template<typename T>
class Fun3 {
inline T fun3(T &x1, T &x2)
{
return std::pow(x1,2.0) + std::pow(x2,2.0);
}
};
template<typename T, typename U>
class Fun5 {
inline T fun5(U &a)
{
return (T(4.0+a*(-2.0),5.0+ a*3.0));
}
};
template<typename F, typename T>
class Min {
void min(F fun1, T& v)
{
double x={10.0};
v=fun1(x);
}
};
int main()
{
double val;
Fun5<double> o5;
Fun3<decltype (o5.fun5)> o3;
Min<???,decltype (o5.fun5)> obj; //What is here?
obj(o3.fun3(o5.fun5),val);
std::cout<<"value = "<<val<<"\n";
return 0;
}
I don't know what will go to commented line.
How can I use a function object (functor) here?
I want to evaluate fun3(fun5(x))
min([](auto x){ return fun3(fun5(x)); }, val);
There's no function composition in C++ standard library (though it can be defined with some effort.)
If you really want fun, at least try lambdas. They are simple.
I'd say stay away from templates in the way you want to use them. I am assuming you want a simple happy life to focus on productive thing and I may be wrong. Pardon.
Still, I worked on your code a bit and would say that don't confuse template and macros. It looks like the case at least to me.
Note that the template actually instantiate the code and for that all you can pass is arguments to whatever types and specify those types while template instantiating.
Here is a code sample at ideone - not exactly same but to show how something can be done.
For min(fun3(fun5),val);
If you really want fun3 behavior, pass it. Dont expect the result to be passed just like it works for macro.
.
#include <iostream>
#include <cmath>
using namespace std;
typedef double (*_typeofFun1)(double&);
typedef double (*_typeofFun3)(double&, double&);
template<typename T>
T fun3(T &x1, T &x2)
{
return std::pow(x1,2.0) + std::pow(x2,2.0);
}
template<typename T, typename U>
U fun5(T t, U &a)
{
//return (T(4.0+a*(-2.0),5.0+ a*3.0));
return t(a,a);
}
template <typename T>
T fun1Param(T& arg)
{
return 2*arg;
}
template<typename F, typename T>
void min(F fun1, T& v)
{
double x={10.0};
v=fun1(x);
}
int main()
{
double val = 1.0;
double d = fun5<_typeofFun3, double> (fun3, val);
fun3<double>(d, val);
min<_typeofFun1>(fun1Param,val);
std::cout<<"value = "<<val<<"\n";
return 0;
}
Here's what I want to do:
#include <vector>
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp =
[](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;})
{
}
int main()
{
std::vector<int> a{1, 2};
f(a);
return 0;
}
But it doesn't work: could not deduce template argument for 'ComparatorType'.
Using a proxy function instead of an actual default argument value works, but seems overly verbose, isn't there a better way? Not to mention it's not the same since now I can't just substitute the default comparator with my own without changing the function name in the client code.
#include <vector>
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp)
{
}
template <class ContainerType>
void f2(ContainerType c)
{
f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}
int main()
{
std::vector<int> a{1, 2};
f2(a);
return 0;
}
without changing the function name in the client code.
You can overload function templates just fine. There is no need to use a different name.
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp)
{
}
template <class ContainerType>
void f(ContainerType c)
{
f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}
You can't make a default function argument contribute to template argument deduction. It's not allowed because it raises some difficult to resolve questions in the deduction process.
Template deduction is performed before default arguments are considered. Also, lambdas are not allowed to appear in unevaluated operands.
You can first assign the default function to a variable. Then you can spell out its type. For example:
auto default_functor = [](int x){ return x > 0; };
template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
return f(x);
}
Now you can use the function as usual:
bool even(int x)
{
return x % 2 == 0;
}
struct Odd {
bool operator()(int x) const
{
return x % 2 == 1;
}
};
void g()
{
function(1); // use default functor
function(1, even); // use a free function
function(1, Odd{}); // use a function object
function(1, [](int x){ return x < 0; }); // use another lambda
}
You don't need to explicitly specify the type.
Note: According to #StoryTeller, this can lead to ODR violation if you use it in a header. In that case, you can use a named functor type:
struct Positive {
constexpr bool operator(int x) const
{
return x > 0;
}
};
inline constexpr Positive default_functor{};
template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
return f(x);
}
I want to write a function in c++ that takes a variable of type int and what it does is that it will define the overloading operator () of a functor and will return that functor as output argument. For example:
template<class Functor>
Functor myFunc(double n)
{
Functor f;
double Functor::operator() (double q)
{ return n*q;}
return Functor;
}
class myClass
{
double operator() ( double q ) const ;
};
Is this proper the way of doing it ?
There's a syntactic sugar for what you're trying to do (wrongly). It's called lambda expressions and this is what it should look like:
auto myFunc(double n)
{
return [n](double q) { return n * q; }
}
If C++11 is not available, you can emulate it like this (which fixes your errors above):
class Functor
{
double m_n;
public:
Functor(double n) : m_n(n) {}
double operator()(double q) const { return m_n * q; }
};
Functor myFunc(double n)
{
return Functor(n);
}
If you wish, you can keep myFunc as a template, but the point is, you can change the behaviour by the functor you pass in, so trying to hardcode operator() inside myFunc does not really make sense, and is not possible.
Making it more generic:
template <typename T>
class Functor
{
T m_n;
public:
Functor(T n) : m_n(n) {}
T operator()(T q) const { return m_n * q; }
};
template <template <typename> class Functor, typename T>
auto myFunc(T n)
{
// we can use perfect forwarding here, but it's far beyond the original question
return Functor<T>(n);
}
Usage:
myFunc<Functor>(2)(3)
Even more generic, for variable amount of parameters captured by a functor (variadic templates):
template <template <typename ...> class Functor, typename ... Ts>
auto myFunc(Ts ... ns)
{
return Functor<Ts...>(ns...);
}
I wanted the ability to write code like this:
SplineFunction<Polynomial<3>> cubicSplineFunction;
// ... here be some additional code to populate the above object ...
auto dydx = cubicSplineFunction.transform<Polynomial<2>>(const Polynomial<3>& cubicSpline){
return cubicSpline.derivative();
};
auto dsdx = cubicSplineFunction.transform<T/*?*/>([](const Polynomial<3>& cubicSpline){
Polynomial<2> dy = cubicSpline.derivative();
Polynomial<4> dsSquared = dy*dy + 1*1;
return [dsSquared](double x){ // Fixed in response to comment: capture by value
return std::sqrt(dsSquared);
};
});
dydx(1.0); // efficient evaluation of cubicSplineFunction's derivative
dsdx(2.0); // efficient evaluation of cubicSplineFunction's arc rate
So I implemented the classes below. But what type should I substitute for T (in line 8) above to denote "something callable with signature double(double)" ?
template<typename S>
struct SplineFunction {
std::vector<S> splines;
auto operator()(double t) const {
int i = static_cast<int>(t);
return splines[i](t - i);
}
template<typename R, typename F>
SplineFunction <R> transform(F f) const {
SplineFunction <R> tfs;
for (const auto& s : splines) {
tfs.splines.push_back(f(s));
}
return tfs;
}
// ... MORE CODE ...
}
template<int N>
struct Polynomial {
std::array<double, N+1> coeffs;
double operator()(double x) const;
Polynomial<N - 1> derivative() const;
// ... MORE CODE ...
}
template<int L, int M>
Polynomial<L+M> operator*(const Polynomial<L>& lhs, const Polynomial<M>& rhs);
template<int L>
Polynomial<L> operator+(Polynomial<L> lhs, double rhs);
// ... MORE CODE ...
template<class F, class R=std::result_of_t<F&(S const&)>>
SplineFunction<R> transform(F f) const
don't pass types expliclty; let them be deduced.
In c++11 do typename std::result_of<F&(S const&)>::type.
Decaying the R type (as in std decay) may also be smart, as SplineFunction stores its template parameter, and decay makes types more suitable for storage.
I'm writing a compiler that compiles to C++ and am having type issues with my C++ code. The language is meant to be lazy, so we have a lazy value wrapper, Chunk. Here is a part of it, along with the problematic code:
#include <functional>
#include <memory>
template<class T>
class Chunk
{
public:
Chunk();
Chunk(std::function<T()> f);
T operator()();
std::function<T()> f_;
private:
std::shared_ptr<T> cache_;
};
template<class T>
T Chunk<T>::operator()()
{
if(cache_ == nullptr)
cache_ = std::make_shared<T>(f_());
return *cache_;
}
template<class T, class F>
T operator*(Chunk<T> t1, Chunk<F> t2)
{
return t1() * t2();
}
template<class T, class... Args>
T apply(Chunk<std::function<T(Args...)>> c, Args... as)
{
return c()(as...);
}
template<class F>
auto toChunk(F f) -> Chunk<decltype(f())>
{
return Chunk<decltype(f())>(f);
}
template<class T, class F>
struct ops
{
static const auto multiply =
toChunk([]() { return ops::multiply_; });
static const auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
};
int main()
{
Chunk<double> t = toChunk([]() { return 1.0; });
Chunk<float> f = toChunk([]() { return 2.0f; });
apply(ops::multiply, t, f);
return 0;
}
I can't figure out a definition of multiply to make this work without getting a used without template parameters error. (There may be a second issue here because multiply_ isn't a std::function, but the compiler breaks on the lack of template parameters first.)
I could write a lot of overloads for every pair of types, but this is just really ugly. I tried making multiply a template variable without a template class, and even though I'm using C++14, got cannot resolve address of overloaded function at multiply_ with this alternative definition:
template<class T, class F>
auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
template<class T, class F>
Chunk<decltype(multiply_)> multiply = toChunk([]() { return multiply_; });
Of course I then changed ops::multiply to simply multiply. Any suggestions to overcome this?
ops is a name of a class template. To refer to members of a class template outside of its definition you need to specify the template arguments.
If you fix this error though, there are going to be more.
I ended up using an entirely different solution. I overloaded apply by adding this second definition:
template<class F, class... Args>
auto apply(F f, Args... as) -> decltype(f(as...))
{
return f(as...);
}
And rewrote multiply as simply:
auto multiply = [](auto x, auto y) { return x * y; };
So our library functions will not be in the lazy wrappers, while user-defined functions (which can't be templates in our language) will.