How to implement transformation of vector of objects? [duplicate] - c++

This question already has answers here:
A positive lambda: '+[]{}' - What sorcery is this? [duplicate]
(1 answer)
Resolving ambiguous overload on function pointer and std::function for a lambda using + (unary plus)
(1 answer)
Closed last month.
I want to implement template function which will transform vector<A> to vector<B> by calling method A::fun() which returns type B.
I implemented it this way:
#include <algorithm>
#include <iostream>
#include <vector>
struct Point {
float x;
float y;
};
template<typename T, typename U>
std::vector<T> getVectorOfValues(const std::vector<U> &objects,
T(*functor)(const U&)) {
std::vector<T> result;
std::transform(std::begin(objects), std::end(objects), std::back_inserter(result), functor);
return result;
}
int main()
{
std::vector<Point> a = { {1,2},{3,4},{5,6},{7,8},{9,10} };
auto y = getVectorOfValues(a, +[](const Point& l){return l.y;});
for(auto a : y) { std::cout << a << " "; }
std::cout << std::endl;
}
It works well untill I need to capture variables by lambda and I have to put + before lambda.
Why does the + sign helps there?
Also I tried to use std::function but it couldn't deduce return type of functor without explicit declaration.
How can I implement this idea in the way where return type of the functor is deduced automaticaly?

Related

C++ Store an expression template inside a class whose objects will be part of a vector

[Extensively edited for clarity and typos, and now with attempted solution, old version at the end]
New version of the question
I have a class which needs to store a functor. The problem is that the functor is an expression template (meaning that each functor is of different type). On top of that I need to collect all the objects of that class in a vector.
Below my attempts:
I do not write the code for the functors as expression templates as it is too long. I will therefore test the code by trying to store two functors of two different classes
struct FunctorTypeA {
double a;
FunctorTypeA(const double ap): a(ap) {}
double operator()(const double x){ return a;}
};
struct FunctorTypeB {
double a, b;
FunctorTypeB(const double ap, const double bp): a(ap), b(bp) {}
double operator()(const double x){ return a+b*x;}
};
I think, correct me if I am wrong, that if the code below works for the two functors above, it should work for any functor constructed with expression templates.
The first idea would be
template <typename functorType> struct myClass {
functorType functor;
myClass(functorType funct): functor(funct){}
};
I can store a functor inside an object of that class with:
FunctorTypeA functor1(1.2);
FunctorTypeB functor2(1.5, 5.0);
myClass myObj1(functor1);
myClass myObj2(functor2);
cout << myObj1.functor(0.2) << " " << myObj1.functor(0.2) << "\n\n";
However I cannot store those objects in an std::vector as they have different types.
Therefore I tried:
struct myClass2Base {
virtual ~TrialClassBase() = default;
virtual double functor(const double x) = 0;
};
template <typename functorType> struct myClass2 : public myClass2Base {
functorType functorStored;
myClass2(functorType funct): functorStored(funct){}
double functor(const double x){return functorStored(x);}
};
and I can construct a vector of those objects as
std::vector<myClass2Base*> vecOfObj;
vecOfObj.push_back(new myClass2(functor1));
cout << vecOfObj[0]->functor(0.3) << "\n\n";
This one works.
Is there a better solution?
Thanks!
Old version of the question
I have a class which needs to store a functor which is an expression template (meaning that each function is of different type). I also need to put the objects of that class in an std::vector.
My Attempt is
struct TrialClassBase{
virtual double get_functor(double) = 0;
};
template <typename derived> struct TrialClass : public TrialClassBase {
derived functor;
TrialClass(derived fun): functor(fun){}
double get_functor(double x) {return functor(x);}
};
std::vector<shared_ptr<TrialClassBase>> vecOfObjs;
Then I try to add an object to the vector. As an example I use an std::function, only as an example: the functor in my case will be an expression template.
std::function<double(double)> funcccc = [](double x){return x*x;};
vecc.emplace_back(TrialClass(funcccc));
cout << vecc[0]->get_functor(0.3) <<"\n\n";
This fails to compile. What mistake am I making? How can I do what I want to do?
Thanks!
I see you have improved your question.
Yes there are debatably better solutions.
One nice solution the std lib offers you, is to use type-erasure using std:function.
#include <vector>
#include <functional>
#include <iostream>
#include <cmath>
struct FunctorTypeA {
double a;
FunctorTypeA(const double ap): a(ap) {}
auto operator()([[maybe_unused]]const double x) const { return a;}
};
int main(){
auto funcVec{std::vector<std::function<double(double)>>{}};
funcVec.push_back(FunctorTypeA{3.14}); // functor allowed
funcVec.push_back([](double x){return x;}); // lambda allowed
funcVec.push_back(sqrt); // function pointer allowed, e.g. C math function
for(auto&& f:funcVec){
std::cout << f(2.0) << '\n';
}
}
This way you don't complicate things with inheritance and pointer casting. Easy to make mistakes there. std::vector and std::function will do all the cleaning up. (That was something you can easily miss in your vector-of-pointers solution)
Note: std::function may perform a dynamic allocation. But so does std::vector and inheritance has vtable overhead.
Your construction of the shared_ptr is invalid
As pointed in the comments:
A base class should always have a virtual destructor
push_back is to be preferred
struct TrialClassBase {
virtual double get_functor(double) = 0;
virtual ~TrialClassBase() = default;
};
template <typename derived> struct TrialClass : public TrialClassBase {
derived functor;
TrialClass(derived fun) : functor(fun) {
}
double get_functor(double x) {
return functor(x);
}
};
std::vector<std::shared_ptr<TrialClassBase>> vecc;
int main() {
std::function<double(double)> funcccc = [](double x) { return x * x; };
vecc.push_back(
std::make_shared<TrialClass<std::function<double(double)>>>(funcccc));
std::cout << vecc[0]->get_functor(0.3) << "\n\n";
}

How to store and call a variable argument function and a vector of values?

In Python, it is possible to store a function pointer with different number of arguments and store the arguments in a list and then unpack the list and call that function like:
def Func(x1, x2):
return x1+x2
ArgList = [1.2, 3.22]
MyClass.Store(Func)
MyClass.FuncPtr(*ArgList)
Is it possible in c++ to do a similar thing?
For example, store the function with the variable-number of inputs and the values in a std::vector and call function pointer by that vector?
I don’t want to define the argument list as a vector.
Is it possible in c++ to do a similar thing?
If you know the arguments(types) at compile-time, of-course you can!
For, instance like/similar to what #Evg suggested, make the Func as a variadic-generic-lambda, and with the support of c++17's std::apply,(for future readers) you could do.
(See a demo)
#include <iostream>
#include <utility> // std::forward
#include <tuple> // std::apply
constexpr auto func_lambda = [](auto&&... args) {
return (std::forward<decltype(args)>(args) + ...); // fold expression
};
int main()
{
std::cout << std::apply(func_lambda, std::make_tuple(1, 2, 3)); // prints 6!
return 0;
}
And now as per your python demo code, you could pack the above idea into to a class-template.
Here, you can avoid the use of std::function, as the Func will be the lambda you pass, and can be stored as compiler deduced lambda unspecified type.
(See Demo Online)
#include <iostream>
#include <utility> // std::forward
#include <tuple> //std::apply, std::make_tuple
// `Func` as variadic-generic-lambda
constexpr auto func_lambda = [](auto&&... args) noexcept {
return (std::forward<decltype(args)>(args) + ...);
};
template<typename Func>
class MyClass final
{
Func mFunction;
public:
explicit MyClass(Func func) // Store: pass the lambda here!
: mFunction{ func }
{}
template<typename... Args> // to execute the `Func` with `Args`!
constexpr auto execute(Args&&... args) const noexcept
{
return std::apply(mFunction, std::make_tuple(std::forward<Args>(args)...));
}
};
int main()
{
MyClass myClass{ func_lambda }; // MyClass.Store(Func)
std::cout << myClass.execute(1.2, 2.82, 3); // MyClass.FuncPtr(*ArgList)
return 0;
}
Output:
7.02
Unfortunately it is not possible to call an arbitrary function passing arbitrary values in a complete dynamic way at runtime. At least some part of the C++ code must compile a static call to a function with the same exact signature.
The problem is that in C++ the parameter passing can only be handled by the compiler and even variadic functions (e.g. printf) where only inspection is performed at runtime normally require a different and simpler calling convention.
One technical problem is that modern ABIs are extremely complex and asymmetrical (e.g. some parameters in registers, some in special FPU registers, some in the stack) and are only handled at compile time.
What you can do is "wrap" the functions you want to be able to call in a function accepting for example an std::vector of generic values and then calling the function passing those parameters converted to the proper type, e.g. something like
Value myabs(const std::vector<Value>& args) {
if (args.size() != 1) throw std::runtime_error("Bad arity");
return Value(fabs(args[0].to<double>()));
}
then it is easy to dynamically call these wrappers because the signature is the same for all of them.
Those wrappers unfortunately must be written (or generated) for each of the functions you need to be able to call so the compiler can actually generate the code needed to call the regular C++ functions.
I am not a template expert, but C++ metaprogramming can be used to generate the wrappers instead of coding each of them manually or writing an external code generator.
This is a very basic example:
typedef Value (*FWrapper)(const std::vector<Value>&);
template<typename RV, typename T1, typename T2, RV (*f)(T1, T2)>
Value wrapper2(const std::vector<Value>& args) {
if (args.size() != 2) throw std::runtime_error("Bad arity");
return f(args[0].to<T1>(), args[1].to<T2>());
}
For example to wrap double atan2(double, double) you can simply write:
FWrapper myatan2 = &wrapper2<double, double, double, &atan2>;
I tried a bit without success to avoid passing explicitly the return value type and number and types of parameters and to extract them instead from the passed function pointer, but may be that is also possible or even practical with recent C++.
The idea is basically to invoke the compiler to build a specific function call on demand when doing a template instantiation.
Not exactly the same thing but in C++ you can apply a combining function to a range of values to produce a single result. std::accumulate can help you here. However, it works with a given range, not variadic arguments.
#include <numeric>
#include <vector>
#include <functional>
#include <iostream>
class MyClass
{
public:
template<typename F, typename T>
T Execute(F &&fn, const T initialValue, const std::vector<T> &values)
{
auto result = std::accumulate(values.begin(), values.end(),
initialValue, std::forward<F>(fn));
return result;
}
};
int main()
{
MyClass cls;
std::vector<double> values = { 1.2, 3.22 };
auto sum = cls.Execute(std::plus<double>{}, 0.0, values);
std::cout << "Sum = " << sum << std::endl;
auto product = cls.Execute(std::multiplies<double>{}, 1.0, values);
std::cout << "Product = " << product << std::endl;
std::vector<int> values2 = { 10, 20 };
auto subtractFrom200 = cls.Execute(std::minus<int>{}, 200, values2);
std::cout << "Subtract from 200 = " << subtractFrom200 << std::endl;
std::vector<std::string> mystrings = {"Hello", " ", " world", ". ", "Bye!"};
auto concatenate = cls.Execute([](std::string a, std::string b){ return a + b ;}, std::string(), mystrings);
std::cout << "Concatenation = " << concatenate << std::endl;
std::vector<double> values3 = {100, 98, 3.5, 50};
auto findMin = [](double a, double b){ return std::min(a, b); };
auto lowest = cls.Execute(findMin, values3.front(), values3);
std::cout << "Min = " << lowest << std::endl;
}
Demo
Note: the fourth parameter to std::accumulate is optional and if omitted it will return the sum of the values. However, you can provide your own binary function if you want to do something else, e.g. multiplication or subtraction.

What is the most efficient way to pass a non generic function?

I am learning functional programming in C++. My intention is to pass a non generic function as argument. I know about the template method, however I would like to restrict the function signature as part of the API design. I worked out 4 different methods example on cpp.sh:
// Example program
#include <iostream>
#include <string>
#include <functional>
typedef int(functor_type)(int);
int by_forwarding(functor_type &&x) {
return x(1);
}
int functor_by_value(functor_type x) {
return x(1);
}
int std_func_by_value(std::function<functor_type> x) {
return x(1);
}
int std_func_by_forwarding(std::function<functor_type> &&x) {
return x(1);
}
int main()
{
std::cout << functor_by_value([](int a){return a;}); // works
std::cout << std_func_by_value([](int a){return a;}); // works
std::cout << std_func_by_forwarding(std::move([](int a){return a;})); // works
//std::cout << by_forwarding([](int a){return a;}); // how to move lambda with forwarding ?
}
Is any of the above attempts correct? If not, how do i achieve my goal?
(based on clarification from comments)
Signature can be restricted by using std::is_invocable:
template<typename x_Action> auto
functor_by_value(x_Action && action)
{
static_assert(std::is_invocable_r_v<int, x_Action, int>);
return action(1);
}
online compiler
Other alternative:
template <typename Func>
auto functor_by_value(Func&& f)
-> decltype(std::forward<Func>(f)(1))
{
return std::forward<Func>(f)(1);
}
however I would like to restrict the function signature as part of the API design.
So restrict it:
#include <functional>
#include <type_traits>
#include <iostream>
/// #tparam F is a type which is callable, accepting an int and returning an int
template
<
class F,
std::enable_if_t
<
std::is_convertible_v<F, std::function<int(int)>>
>* = nullptr
>
int myfunc(F &&x) {
return x(1);
}
int main()
{
auto a = myfunc([](int x) { std::cout << x << std::endl; return 1; });
// does not compile
// auto b = myfunc([]() { std::cout << "foo" << std::endl; return 1; });
}
As usual, this depends on how good your compiler is today, and how good it will be in the future.
Currently, compilers are not very good at optimizing std::function. Surprisingly, std::function is a complicated object that sometimes has to allocate memory to maintain stateful lambda functions. It also complicates matters that std::function has to be able to refer to member function, regular functions, and lambdas, and do it in a transparent manner. This transparency has a hefty runtime cost.
So, if you want the fastest possible code, you should be careful with std::function. For that reason the first variant is the fastest (on today's compilers):
int functor_by_value(functor_type x) {
return x(1);
}
It simply passes a pointer to a function.
When stateful lambdas are involved you have only two options. Either pass the lambda as a template argument, or convert to std::function. Hence, if you want the fastest code possible with lambdas (in today's compilers), you'd pass the function as a templated argument.
Since a lambda function may have a big state, passing it around may copy the big state (when copy elision is not possible). GCC will construct the lambda directly on the parameter list (with no copy), but a nested function will invoke a copy constructor for the lambda. To avoid that, either pass it by const reference (in that case it can't be mutable), or by rvalue reference:
template<class Func>
void run2(const Func & f)
{
std::cout << "Running\n";
f();
}
template<class Func>
void run(const Func & f)
{
run2(f);
}
int main()
{
run([s=BigState()]() { std::cout << "apply\n"; });
return 0;
}
Or:
template<class Func>
void run2(Func && f)
{
f();
}
template<class Func>
void run(Func && f)
{
run2(std::forward<Func>(f));
}
int main()
{
run([s=BigState()]() { std::cout << "apply\n"; });
return 0;
}
Without using references, the BigState() will be copied when the lambda is copied.
UPDATE:
After reading the question again I see that it wants to restrict the signature
template<typename Func,
typename = std::enable_if_t<
std::is_convertible_v<decltype(Func(1)), int>>>
void run2(const Func & f)
{
std::cout << "Running\n";
f();
}
This will restrict it to any function that can accept int (possibly with an implicit cast), and returns an int or any type that is implicitly cast to int. However, if you want to accept only function-like objects that accept exactly int and return exactly int you can see if the lambda is convertible to std::function<int(int)>

Use pack parameter in template vector & Lambda - c++

I am trying variadic template pack inside lambda function with vector.
Learning the c++ programming langage book, it's said "If you need to capture a variadic template argument, use ..." (with a simple example).
I am not able to compile it, my aim is just to be able to print the variadic type inside my lambda:
#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
template<typename... vectType>
void printAllElements(vector<vectType...>& nbList, ostream& output, int nbToTest){
for_each(begin(nbList),end(nbList),
[&vectType...](vectType... x){
vectType... v;
output << x << endl;
output << typeid(v).name() << endl;
}
);
}
int main() {
vector<int> myVect {10,20,156,236};
printAllElements(myVect,cout, 4);
}
StackTrace:
learnC++/main.cpp:10:7: error: 'vectType' in capture list does not name a variable
[&vectType...](vectType... x){
^
learnC++/main.cpp:11:15: error: only function and template parameters can be parameter packs
vectType... v;
^
learnC++/main.cpp:12:7: error: variable 'output' cannot be implicitly captured in a lambda with no capture-default specified
output << x << endl;
Regards
Update 1:
Ok so I update this question to add the two code of Stroustrup I concataned with his advices.
Lambda & Vector
Void print_modulo(const vector<int>& v, ostream& os, int m){
for_each(begin(b),end(v),
[&os,m](int x){ if (x%m==0 os << w << '\n');}
}
The version using lambda is a clear winner. But if you really want a
name, you can just provide one ..
Capture template
If you need to capture template argument, use ... For example:
template<typename... Var>
void algo(int s, Var... v){
auto helper = [&s,&v...]{return s*(h1(v...)+h2(v...);)};
}
h1 & h2 are simple examples functions
I will try to explain what is wrong in your code, but to be truly understood, you need to read some good books.
std::vector is a homogeneous container, all its elements have only one same type. This vector<vectType...> is pointless. For example, std::vector<int> has all int elements; there is no such a thing std::vector<int, double, short>. Thus if you want to print the typeid for some different types, your approach is wrong from the beginning.
In your own code [&vectType...], those vectType are types, that's also pointless. In your quoted code [&s,&v...], those v are variables, thus correct.
Such vectType... v; declaration is invented by yourself, it's not C++.
The following is a simple example in C++14 if you want to print variables' typeid in a generic way:
#include <iostream>
template<class... Args>
void print_all_typeid(Args const &...args)
{
auto dumb = [] (auto... x) {};
auto printer = [] (auto const &x) {
std::cout << typeid(x).name() << "\n";
return true;
};
dumb(printer(args)...);
}
int main() {
print_all_typeid(std::cin, 12, std::cout, 1L, 2.0, 3.f);
}

C++11: Cannot capture `this` when trying to capture member of class in lambda function

I'm writing a simple test to see how C++11 Lambdas can be used for the purpose of maximizing code reuse. I have a function, fill_vector() and in one case I'd like it to simply fill a vector with random numbers, but in another case I'd like it to also provide me with the maximum of those numbers.
Here's what I have so far:
#include <iostream>
#include <random>
#include <vector>
#include <algorithm>
#include <iterator>
template <class Function>
void fill_vector(std::vector<int> &v, Function side)
{
for(auto i=v.begin(); i!=v.end(); ++i)
{
*i = rand() % 100;
}
side.lambda(v);
}
class null_test
{
public:
constexpr static auto lambda = [] (std::vector<int> x) { };
};
class test
{
public:
test() : max(0) { }
int max;
static auto lambda = [=] (std::vector<int> x) { max =
std::max_element(x.begin(),x.end()); };
};
int main()
{
std::vector<int> v(20);
null_test n;
fill_vector(v,n);
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;
std::vector<int> v2(20);
test t;
fill_vector(v2,t);
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;
std::cout << t.max << std::endl;
return 0;
}
Which results in the error: ‘this’ was not captured for this lambda function, pointing at my lambda defined in test. I've tried all sorts of capture statements and can't seem to get anything to work. What am I missing?
Also, is it possible to use a lambda inside the loop of fill_vector that could, say, extract every nth element filled? My goal here is to be able to reuse a function like fill_vector as much as possible for other functions that might need slight variations of it in a bigger project.
Looking at your class test:
class test
{
public:
int max;
static auto lambda = [=] (std::vector<int> x) {
max = std::max_element(x.begin(),x.end());
};
};
There are several problems here:
operator() on a lambda is const, and you are trying to modify a member.
You are trying to assign the value to an external variable, but are capturing it by-value, so even if you made the lambda mutable, nothing would happen.
You are trying to assign a member of a class using a static function that does not take an instance of that class.
As dyp points out, std::max_element returns an iterator, not the actual element.
The lambda you want to write probably looks like this:
test t;
std::vector<int> v2(20);
fill_vector(v2, [&t](const std::vector<int>& x){
t.max = *std::max_element(x.begin(), x.end());
});
Just change your fill_vector() function to take a callable, rather than something that has a callable.