To make more sence for the question title consider the following code:
template <typename T>
void write(const T& /*data*/)
{
// use data as const
}
template <typename T>
void read(T& /*data*/)
{
// modify data
}
struct S {
int a;
int b;
// a lot of primitive types here
};
void output(const S& s)
{
write(s.a);
write(s.b);
// ...
}
void input(S& s)
{
read(s.a);
read(s.b);
// ...
}
int main()
{
S s;
input(s);
output(s);
}
I have write and read functions that manipulate primitive data like int, double etc. I have several struct types like S that contains a lot of primitive data members, and I need to input and output such types via corresonding functions input and output (there are many of overloads for distinct types). As you can see the content of output and input functions mostly the same, only the inner functions and type constness are different. I would like to make some generic (template) function use to eliminate code duplicates from input/output functions.
I think the template signature will be the following (but I can miss something):
template <typename F, typename T>
void use(T& t) { ... }
So I could call the use function from input/output like this:
use<write, S>(s); // in output function
use<read, S>(s); // in input fuction
How to archive this (or similar) behaviour to eliminate code duplications? I'm using C++14.
template <typename S, typename F>
void use(S&& s, F&& f)
{
f(s.a);
f(s.b);
f(s.c);
}
Usage:
use(s, [](const auto& x){ write(x); });
use(s, [](auto& x) { read(x); });
live example on wandbox.org
If you need multiple types:
template <typename S, typename Target>
using EnableFor = std::enable_if_t<std::is_same_v<std::decay_t<S>, Target>>;
template <typename S, typename F>
auto use(S&& s, F&& f) -> EnableFor<S, S0>
{
f(s.a);
f(s.b);
f(s.c);
}
template <typename S, typename F>
auto use(S&& s, F&& f) -> EnableFor<S, S1>
{
f(s.d);
f(s.e);
f(s.f);
}
Usage:
int main()
{
S0 s0;
use(s0, [](const auto& x){ write(x); });
use(s0, [](auto& x) { read(x); });
S1 s1;
use(s1, [](const auto& x){ write(x); });
use(s1, [](auto& x) { read(x); });
}
live example on wandbox.org
You can define an interface of the template being used:
template<class M, class S>
void use(S &&s) {
M::method(s.a);
M::method(s.b);
};
Then implement it:
template <typename T>
void write(const T& /*data*/)
{
// use data as const
}
struct writer {
template <typename T>
static void method(const T& t)
{
write(t);
}
};
Now you can use it:
use<writer>(s);
For read, it's the same:
struct reader {
template <typename T>
static void method(T& t)
{
read(t);
}
};
use<reader>(s);
I believe I understood what you want, but it is impossible. Currently there is no way to implement in C++ generic streaming for all classes. One would need access to information like number of fields the class has, their relative address as well as type in compile time.
Currently they are working on adding this to C++ for many years, seek Reflection TS. As far as I know it won't be ready for C++20.
However, you can organize your code so that each read/write method is easy to implement. For example:
class A : public B, public C
{
private:
vector<int> m_v;
int m_x;
};
Then implement write for it as
template<>
void write(const A& a)
{
write((const B&)a);
write((const C&)a);
write(a.m_v);
write(a.m_x);
}
While for common data structures like std::vector<T> implement write via write<T>. It takes time but making it technical and using redirections can save a lot of code and time.
(You need to make write a friend function, or a member function to let it access private members)
Related
I'm trying to write a demo that implements the fmap in Haskell with continuation, and my code looks like this:
#include <cstdio>
#include <functional>
template <typename X>
using Callback = std::function<void(X)>;
template <typename X, typename Y>
using Fun = std::function<Y(X)>;
template <typename X, typename Y>
struct F_map;
template <typename X>
struct __F {
virtual void operator()(Callback<X>&& callback) = 0;
virtual __F<X>* self() { return this; }
template <typename Y>
auto map(Fun<X, Y>&& f) { return F_map(self(), f); }
};
template <typename X>
struct F_id : __F<X> {
const X x;
F_id(const X& x) : x(x) {}
__F<X>* self() override { return this; }
void operator()(Callback<X>&& callback) override { callback(x); }
};
template <typename X, typename Y>
struct F_map : __F<Y> {
__F<X>* upstream;
Fun<X, Y> f;
F_map(__F<X>* upstream, const Fun<X, Y>& f) : upstream(upstream), f(f) {}
__F<Y>* self() override { return this; }
void operator()(Callback<Y>&& callback) override {
upstream->operator()([=](X&& x) {
callback(f(x));
});
}
};
int main(int argc, char* argv[]) {
auto f =
F_id(10)
.map<int>([](int x) { return x + 2; })
.map<const char*>([](int x) { return "1, 2, 3"; });
f([](const char* x) { printf("%s\n", x); });
return 0;
}
That works fine, but the map<int> and map<const char*> looks ugly. I think these declarations can be omitted, but if I remove that I got an error message that says "no instance of function template "F_id::map [with X=int]" matches the argument list".
Any idea to remove these template arguments?
There are multiple kinds of polymorphism in C++. By polymorphism, I mean whenever a single variable in code has different implementation types.
There is classic C++ inheritance and virtual based polymorphism. There is type erasure based polymorphism. And there is static polymorphism of templates.
In many senses, these kinds of polymorphism are opposed to each other. If you use one when you should be using the other, it is like using covariance when you should be using contravariance. Your code might stumble along, but it will only work when forced, like taking a square peg and a round hole and a big hammer.
Your <int> requirement is an example of using the wrong kind of polymorphism, and the <int> is the hammer smashing it into the wrong-shaped hole.
You are attempting to use
template <typename X>
using Callback = std::function<void(X)>;
and
template <typename X, typename Y>
using Fun = std::function<Y(X)>;
as pattern matchers. They aren't pattern matchers, even if in specific cases they can be used as pattern matchers. Callback and Fun are a type erasers.
Callback<X> takes anything that can be called with something that can be converted from an X, and stores it. Then forgets almost every other fact about it (well, it remembers how to copy it, its typeid, and a few other random facts).
Fun<X,Y> takes anything that can be called with something that can be converted from an X, and whose return value can then be converted to a Y. It then forgets almost every other fact about it.
Here:
template <typename Y>
auto map(Fun<X, Y>&& f) { return F_map(self(), f); }
you are trying to use it to say "I accept an f. Please find me a Y that would match this f".
This is pattern matching. Type erasure and pattern matching are opposite operations.
This is a really common mistake. With classic inheritance, they sometimes end up being the same thing.
std::function is for forgetting information about something, being able to store it, then later using only the parts you remember.
The first question is, do you need to pattern match, or do you need a type function here?
Probably you are good with a type function.
template <class F, class R = std::invoke_result_t<F, X>>
F_map<X,R> map(F&& f) { return {self(), std::forward<F>(f)}; }
here we map the incoming F to its return value R.
Your code has other issues. Like dangling pointers. Also, it insists on knowing what types the callables use; in C++, you can ... just not bother knowing that.
So, using the CRTP for static polymorphism, and mechanically forgetting what types I work on an replacing them with non-type erased code, I get:
#include <cstdio>
#include <type_traits>
template <class Upstream, class F>
struct F_map;
template<class D>
struct mappable
{
template <class F>
F_map<D, F> map(F const& f) { return F_map(static_cast<D*>(this), f); }
};
template <class Upstream, class F>
struct F_map:
mappable<F_map<Upstream, F>>
{
Upstream* upstream;
F f;
F_map(Upstream* upstream, const F& f) : upstream(upstream), f(f) {}
template<class Callback>
void operator()(Callback&& callback) {
(*upstream)([=](auto&& x) {
callback(f(decltype(x)(x)));
});
}
};
template <typename X>
struct F_id:
mappable<F_id<X>>
{
const X x;
F_id(const X& x) : x(x) {}
template<class Callback>
void operator()(Callback&& callback) { callback(x); }
};
int main(int argc, char* argv[]) {
auto f =
F_id(10)
.map([](int x) { return x + 2; })
.map([](int x) { return "1, 2, 3"; });
f([](const char* x) { printf("%s\n", x); });
return 0;
}
Live example.
I still think you are following dangling pointers, but I am not sure.
The return value of map stores a pointer to the object we call it on, and that object was a temporary destroyed when we made f.
To fix the Upstream* problem, I'd do this:
template <class Upstream, class F>
struct F_map;
template<class D>
struct mappable
{
template <class F>
F_map<D, F> map(F const& f) const { return {*static_cast<D const*>(this), f}; }
};
template <class Upstream, class F>
struct F_map:
mappable<F_map<Upstream, F>>
{
Upstream upstream;
F f;
F_map(Upstream const& upstream, const F& f) : upstream(upstream), f(f) {}
template<class Callback>
void operator()(Callback&& callback) const {
upstream([=](auto&& x) {
callback(f(decltype(x)(x)));
});
}
};
template <typename X>
struct F_id:
mappable<F_id<X>>
{
const X x;
F_id(const X& x) : x(x) {}
template<class Callback>
void operator()(Callback&& callback) const { callback(x); }
};
copy upstream by value.
If you don't want to provide template arguments to __F::map, you can add another map template that accepts an arbitrary callable, and you can use the type of that callable to figure out the return type:
template <typename F> // <-- any function
auto map(F&& f) { return F_map<X, decltype(f(X{}))>(self(), f); }
// ^ ^^^^^^^^^^^^^^^^ argument, and return type
Note that you now need to specify the template parameters to F_map, but you have the needed information to do that, and is not something the caller has to worry about.
Now this call works:
auto f =
F_id(10)
.map([](int x) { return x + 2; })
.map([](int x) { return "1, 2, 3"; });
Here's a demo.
As pointed out by Marek R in a comment, and as apparent from the demo with Clang, you have some bug in your code that causes a run-time error. You should fix that.
Also, as pointed out by Yakk-Adam Nevraumont in a comment, names containing double underscores __ are reserved for the implementation. Don't use such names in your code.
I require a simple way to obtain the count / length / size of an object of class T where T is some sort of collection type, such as a std::map, std::list, std::vector, CStringArray, CString, std::string, …
For most of the standard types, T::size() is the correct answer, for most of the MFC classes T::GetSize() is correct and for CString, it is T::GetLength().
I want to have a like:
template <typename T> auto size(const T & t)
...which evaluates to the correct member function call.
It seems like there should be a simple way to invoke a traits template on T which has a size(const T & t) member, which itself uses SFINAE to exist or not exist, and if it exists, then it is by definition calling an appropriate t.size_function() to return the count of elements in that instance of a T.
I could write an elaborate has_member type-trait template - there are a few examples on stackoverflow - all of them quite convoluted for what seems to me "there must be a simpler approach". With C++ 17, it seems like this issue should be easily and elegantly solved?
These discussions here and here seems to use an inelegant solution with some of the answers using preprocessor macros to get the job done. Is that still necessary?
But... surely, there must be a way to use the fact that calling the correct member function on a T is compilable, and calling the wrong one fails to compile - can't that be used directly to create the correct type traits wrapper for a given type T?
I would like something along the lines of:
template <typename T>
auto size(const T & collection)
{
return collection_traits<T>::count(collection);
}
Where the exact specialization of collection_traits<T> is selected because it is the only one that fits for T (i.e. it calls the correct instance method).
You can use expression SFINAE and multiple overloads.
The idea is as follows: check if x.size() is a valid expression for your type - if it is, invoke and return it. Repeat for .getSize and .getLength.
Given:
struct A { int size() const { return 42; } };
struct B { int getSize() const { return 42; } };
struct C { int GetLength() const { return 42; } };
You can provide:
template <typename T>
auto size(const T& x) -> decltype(x.size()) { return x.size(); }
template <typename T>
auto size(const T& x) -> decltype(x.getSize()) { return x.getSize(); }
template <typename T>
auto size(const T& x) -> decltype(x.GetLength()) { return x.GetLength(); }
Usage:
int main()
{
size(A{});
size(B{});
size(C{});
}
live example on wandbox.org
This solution is easy to extend and seamlessly works with containers that are templatized.
What if a type exposes two getters?
The solution above would result in ambiguity, but it's easy to fix by introducing a ranking/ordering that solves that.
Firstly, we can create a rank class that allows us to arbitrarily prioritize overloads:
template <int N> struct rank : rank<N - 1> { };
template <> struct rank<0> { };
rank<N> is implicitly convertible to rank<N - 1>. An exact match is better than a chain of conversions during overload resolution.
Then we can create a hierarchy of size_impl overloads:
template <typename T>
auto size_impl(const T& x, rank<2>)
-> decltype(x.size()) { return x.size(); }
template <typename T>
auto size_impl(const T& x, rank<1>)
-> decltype(x.getSize()) { return x.getSize(); }
template <typename T>
auto size_impl(const T& x, rank<0>)
-> decltype(x.GetLength()) { return x.GetLength(); }
Finally we provide an interface function that begins the dispatch to the right size_impl overload:
template <typename T>
auto size(const T& x) -> decltype(size_impl(x, rank<2>{}))
{
return size_impl(x, rank<2>{});
}
Using a type like D below
struct D
{
int size() const { return 42; }
int getSize() const { return 42; }
int GetLength() const { return 42; }
};
will now choose the rank<2> overload of size_impl:
live example on wandbox
The simplest solution, IMO, is function overloading.
// Default implementation for std containers.
template <typename Container>
std::size_t size(Container const& c) { return c.size(); }
// Overloads for others.
std::size_t size(CStringArray const& c) { return c.GetSize(); }
std::size_t size(CString const& c) { return c.GetLength(); }
// ... etc.
You need expression SFINAE, and you must play nice with other types which might decide to conform to both interfaces, so study std::size().
The goal is to augment std::size() to work on all types which follow at least one of the conventions, as long as they don't mess up trying to follow any of them.
#include <type_traits>
#include <iterator>
namespace internal {
// Avoid conflict with std::size()
template <class C>
auto size_impl(const C& c, int) -> decltype((void)c.size());
// Avoid conflict with std::size()
template <class T, std::size_t N>
void size_impl(const T (&array)[N], int);
template <class C>
constexpr auto size_impl(const C& c, long)
noexcept(noexcept(c.GetLength()))
-> decltype(c.GetLength())
{ return c.GetLength(); }
template <class C>
constexpr auto size_impl(const C& c, long long)
noexcept(noexcept(c.getSize()))
-> decltype(c.getSize())
{ return c.getSize(); }
};
template <class T>
using enable_if_not_void_t = std::enable_if_t<!std::is_void<T>(), T>;
using std::size;
template <class C>
constexpr auto size(const C& c)
noexcept(noexcept(internal::size_impl(c, 0)))
-> enable_if_not_void_t<decltype(internal::size_impl(c, 0))>
{ return internal::size_impl(c, 0); }
You can get arbitrary levels of precedence for extending things using templates and inheritance:
template <std::size_t N>
struct priority : priority<N - 1> {};
template <>
struct priority<0> {};
Something like the proposed Abbreviated Lambdas for Fun and Profit would greatly simplify things.
I am trying to implement a resource protection class which would combine data along with a shared mutex (actually, QReadWriteLock, but it's similar). The class must provide the method to apply a user-defined function to the data when the lock is acquired. I would like this apply method to work differently depending on the function parameter (reference, const reference, or value). For example, when the user passes a function like int (const DataType &) it shouldn't block exclusively as we are just reading the data and, conversely, when the function has the signature like void (DataType &) that implies data modification, hence the exclusive lock is needed.
My first attempt was to use std::function:
template <typename T>
class Resource1
{
public:
template <typename Result>
Result apply(std::function<Result(T &)> &&f)
{
QWriteLocker locker(&this->lock); // acquire exclusive lock
return std::forward<std::function<Result(T &)>>(f)(this->data);
}
template <typename Result>
Result apply(std::function<Result(const T &)> &&f) const
{
QReadLocker locker(&this->lock); // acquire shared lock
return std::forward<std::function<Result (const T &)>>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
But std::function doesn't seem to restrict parameter constness, so std::function<void (int &)> can easily accept void (const int &), which is not what I want. Also in this case it can't deduce lambda's result type, so I have to specify it manually:
Resource1<QList<int>> resource1;
resource1.apply<void>([](QList<int> &lst) { lst.append(11); }); // calls non-const version (ok)
resource1.apply<int>([](const QList<int> &lst) -> int { return lst.size(); }); // also calls non-const version (wrong)
My second attempt was to use std::result_of and return type SFINAE:
template <typename T>
class Resource2
{
public:
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f)
{
QWriteLocker locker(&this->lock); // lock exclusively
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const
{
QReadLocker locker(&this->lock); // lock non-exclusively
return std::forward<F>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
Resource2<QList<int>> resource2;
resource2.apply([](QList<int> &lst) {lst.append(12); }); // calls non-const version (ok)
resource2.apply([](const QList<int> &lst) { return lst.size(); }); // also calls non-const version (wrong)
Mainly the same thing happens: as long as the object is non-const the mutable version of apply gets called and result_of doesn't restrict anything.
Is there any way to achieve this?
You may do the following
template <std::size_t N>
struct overload_priority : overload_priority<N - 1> {};
template <> struct overload_priority<0> {};
using low_priority = overload_priority<0>;
using high_priority = overload_priority<1>;
template <typename T>
class Resource
{
public:
template <typename F>
auto apply(F&& f) const
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
template <typename F>
auto apply(F&& f)
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
private:
template <typename F>
auto apply_impl(F&& f, low_priority) -> decltype(f(std::declval<T&>()))
{
std::cout << "ReadLock\n";
return std::forward<F>(f)(this->data);
}
template <typename F>
auto apply_impl(F&& f, high_priority) -> decltype(f(std::declval<const T&>())) const
{
std::cout << "WriteLock\n";
return std::forward<F>(f)(this->data);
}
private:
T data;
};
Demo
Jarod has given a workaround, but I'll explain why you cannot achieve that this regular way.
The problem is that:
Overload resolution prefers non-const member functions over const member functions when called from a non-const object
whatever object this signature void foo(A&) can accept, void foo(const A&) can also the same object. The latter even has a broader binding set than the former.
Hence, to solve it, you will have to at least defeat point 1 before getting to 2. As Jarod has done.
From your signatures (see my comment annotations):
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f) //non-const member function
{
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const //const member function
{
return std::forward<F>(f)(this->data);
}
When you call it like:
resource2.apply([](QList<int> &lst) {lst.append(12); }); //1
resource2.apply([](const QList<int> &lst) { return lst.size(); }); //2
First of all, remember that resource2 isn't a const reference. Hence, the non-const membr function of apply will always be prefered by Overload resolution.
Now, taking the case of the first call //1, Whatever that lambda is callable with, then then the second one is also callable with that object
A simplified mock-up of what you are trying to do is:
struct A{
template<typename Func>
void foo(Func&& f); //enable if we can call f(B&);
template<typename Func>
void foo(Func&& f) const; //enable if we can call f(const B&);
};
void bar1(B&);
void bar2(const B&);
int main(){
A a;
a.foo(bar1);
a.foo(bar2);
//bar1 and bar2 can be both called with lvalues
B b;
bar1(b);
bar2(b);
}
As I understand it, you want to discriminate a parameter that's a std::function that takes a const reference versus a non-constant reference.
The following SFINAE-based approach seems to work, using a helper specialization class:
#include <functional>
#include <iostream>
template<typename ...Args>
using void_t=void;
template<typename Result,
typename T,
typename lambda,
typename void_t=void> class apply_helper;
template <typename T>
class Resource1
{
public:
template <typename Result, typename lambda>
Result apply(lambda &&l)
{
return apply_helper<Result, T, lambda>::helper(std::forward<lambda>(l));
}
};
template<typename Result, typename T, typename lambda, typename void_t>
class apply_helper {
public:
static Result helper(lambda &&l)
{
std::cout << "T &" << std::endl;
T t;
return l(t);
}
};
template<typename Result, typename T, typename lambda>
class apply_helper<Result, T, lambda,
void_t<decltype( std::declval<lambda>()( std::declval<T>()))>> {
public:
static Result helper(lambda &&l)
{
std::cout << "const T &" << std::endl;
return l( T());
}
};
Resource1<int> test;
int main()
{
auto lambda1=std::function<char (const int &)>([](const int &i)
{
return (char)i;
});
auto lambda2=std::function<char (int &)>([](int &i)
{
return (char)i;
});
auto lambda3=[](const int &i) { return (char)i; };
auto lambda4=[](int &i) { return (char)i; };
test.apply<char>(lambda1);
test.apply<char>(lambda2);
test.apply<char>(lambda3);
test.apply<char>(lambda4);
}
Output:
const T &
T &
const T &
T &
Demo
The helper() static class in the specialized class can now be modified to take a this parameter, instead, and then use it to trampoline back into the original template's class's method.
As long as the capture lists of your lambdas are empty, you can rely on the fact that such a lambda decays to a function pointer.
It's suffice to discriminate between the two types.
It follows a minimal, working example:
#include<iostream>
template <typename T>
class Resource {
public:
template <typename Result>
Result apply(Result(*f)(T &)) {
std::cout << "non-const" << std::endl;
return f(this->data);
}
template <typename Result>
Result apply(Result(*f)(const T &)) const {
std::cout << "const" << std::endl;
return f(this->data);
}
private:
T data;
};
int main() {
Resource<int> resource;
resource.apply<void>([](int &lst) { });
resource.apply<int>([](const int &lst) -> int { return 42; });
}
Suppose I have an asynchronous functional map primitive which takes a std::vector as input and returns a std::future to a Container of my choice as output:
template<class Container, class T, class Function>
std::future<Container> async_map(const std::vector<T>& in, Function f)
{
return std::async([=]
{
Container result(in.size());
for(size_t i = 0; i < in.size(); ++i)
{
result[i] = f(in[i]);
}
return result;
});
}
I'd like to build an analogous async_for_each function by adapting async_map:
template<class T, class Function>
std::future<void> async_for_each(const std::vector<T>& in, Function f);
The problem is that async_for_each returns std::future<void>, while async_map returns std::future<Container>, and void is not a Container.
I can get something close to what I want by constructing a type which fulfills the Container requirements but ignores assignments to it (empty_container in my initial attempt), but a std::future of this type is still not std::future<void>.
I have the following constraints on my solution:
There must be only one implementation of async_map, with the given function signature (i.e., no async_map<void> specialization)
There must be only one std::future created (i.e., no .then()-style continuation)
I was hoping there is an efficient way to convert between std::futures of related types (or cast a std::future<T> to std::future<void>), but the answer to this question suggests it is not possible.
Random ideas:
Can async_for_each wrap its function in a clever way to solve this problem?
Can the type used for Container act like void in async_for_each, but act like Container in async_map?
My initial attempt is below. Is it possible to build what I want given these constraints?
#include <future>
#include <vector>
#include <iostream>
template<class Container, class T, class Function>
std::future<Container> async_map(const std::vector<T>& in, Function f)
{
return std::async([=]
{
Container result(in.size());
for(size_t i = 0; i < in.size(); ++i)
{
result[i] = f(in[i]);
}
return result;
});
}
struct empty_container
{
empty_container(size_t) {}
struct empty
{
template<class T>
empty operator=(const T&) const { return empty(); }
};
empty operator[](size_t) { return empty(); }
};
template<class Function>
struct invoke_and_ignore_result
{
Function f;
template<class T>
empty_container::empty operator()(T&& x) const
{
f(std::forward<T>(x));
return empty_container::empty();
}
};
template<class T, class Function>
//std::future<void> async_for_each(const std::vector<T>& in, Function f)
std::future<empty_container> async_for_each(const std::vector<T>& in, Function f)
{
invoke_and_ignore_result<Function> g{f};
std::future<empty_container> f1 = async_map<empty_container>(in, g);
return f1;
}
int main()
{
std::vector<int> vec(5, 13);
async_for_each(vec, [](int x)
{
std::cout << x << " ";
}).wait();
std::cout << std::endl;
return 0;
}
I think you are using the wrong primitive.
Here I build everything up with a different primitive -- a sink.
A sink can consume data via operator()(T&&)&. It then returns some result via operator()()&&.
Here is a async_sink function:
template<class Container, class Sink>
std::future<std::result_of_t<std::decay_t<Sink>()>>
async_sink(Container&& c, Sink&& sink)
{
return std::async(
[c=std::forward<Container>(c), sink=std::forward<Sink>(sink)]
{
for( auto&& x : std::move(c) ) {
sink( x );
}
return std::move(sink)();
});
}
Here is an implementation of a sink that puts things into a container, then returns it:
template<class C>
struct container_sink_t {
C c;
template<class T>
void operator()( T&& t ){
c.emplace_back( std::forward<T>(t) );
}
C operator()()&&{
return std::move(c);
}
};
Here is a sink that takes a function and a sink and composes them:
template<class F, class S>
struct compose_sink_t {
F f;
S s;
template<class T>
void operator()(T&& t){
s(
f(std::forward<T>(t))
);
}
std::result_of_t<S()> operator()()&&{
return std::move(s)();
}
};
template<class C, class F>
compose_sink_t<std::decay_t<F>, container_sink_t<C>>
transform_then_container_sink( F&& f ) {
return {std::forward<F>(f)};
}
Here is a sink that takes a function, calls it, and returns void:
template<class F>
struct void_sink_t {
F f;
template<class T>
void operator()(T&& t)
{
f(std::forward<T>(t));
}
void operator()() {}
};
template<class F>
void_sink_t<std::decay_t<F>> void_sink(F&&f){return {std::forward<F>(f)}; }
now your map is:
template<class Container, class T, class Function>
std::future<Container> async_map(const std::vector<T>& in, Function f)
{
return async_sink(
in,
transform_then_container_sink<Container>(std::forward<F>(f))
);
}
and your for_each is:
template<class T, class Function>
std::future<void> async_for_each(const std::vector<T>& in, Function f)
{
return async_sink(
in,
void_sink(std::forward<F>(f))
);
}
I freely use C++14 features, because they made the code better. You can replace the move-into-container with a copy for a touch less efficiency, and write your own _t aliases.
The above code has not been tested or run, so there are probably bugs in it. There is one issue I'm uncertain of -- can a lambda returning void end with a return void_func() in that context? -- but as that uglyness is in one spot, it can be worked around even if it doesn't work.
There are a lot of impressive Boost libraries such as Boost.Lambda or Boost.Phoenix which go a long way towards making C++ into a truly functional language. But is there a straightforward way to create a composite function from any 2 or more arbitrary functions or functors?
If I have: int f(int x) and int g(int x), I want to do something like f . g which would statically generate a new function object equivalent to f(g(x)).
This seems to be possible through various techniques, such as those discussed here. Certainly, you can chain calls to boost::lambda::bind to create a composite functor. But is there anything in Boost which easily allows you to take any 2 or more functions or function objects and combine them to create a single composite functor, similar to how you would do it in a language like Haskell?
To anyone stumbling onto this page, there's a great blog post on this subject from bureau14:
http://blog.quasardb.net/function-composition-in-c11/
This takes advantage of the new features in C++ 11 as well as using boost.
Stumbling upon this question, I'd like to point out to anyone who comes across this today that this is possible with a relatively elegant syntax using just the standard library and a few helper classes thanks to decltype, auto, and perfect forwarding.
Defining these two classes:
template <class Arg, class ArgCall, class OuterCall>
class pipe {
private:
ArgCall argcall;
OuterCall outercall;
public:
typedef pipe<Arg, ArgCall, OuterCall> this_type;
pipe(ArgCall ac, OuterCall oc) : argcall(ac), outercall(oc) {}
auto operator()(Arg arg) -> decltype(outercall(argcall(arg))) {
return outercall(argcall(arg));
}
template <class NewCall>
pipe<Arg, this_type, NewCall> operator[](NewCall&& nc) {
return {*this, std::forward<NewCall>(nc)};
}
};
template <class Arg>
class pipe_source {
public:
typedef pipe_source<Arg> this_type;
Arg operator()(Arg arg) {
return arg;
}
template <class ArgCall, class OuterCall>
static pipe<Arg, ArgCall, OuterCall> create(ArgCall&& ac, OuterCall&& oc) {
return {std::forward<ArgCall>(ac), std::forward<OuterCall>(oc)};
}
template <class OuterCall>
pipe<Arg, this_type, OuterCall> operator[](OuterCall&& oc) {
return {*this, std::forward<OuterCall>(oc)};
}
};
A simple program:
int f(int x) {
return x*x;
}
int g(int x) {
return x-2;
}
int h(int x) {
return x/2;
}
int main() {
auto foo = pipe_source<int>::create(f, g);
//or:
auto bar = pipe_source<int>()[g][h];
std::cout << foo(10) << std::endl;
std::cout << bar(10) << std::endl;
return 0;
}
This has the added benefit that once it's in a pipe, as long as the return type is correct you can add another function f to the chain with pipe[f].
Then:
$ g++ test.cpp -o test -std=c++11
$ ./test
98
4
$
I don't know of anything that supports the syntax you wish for currently. However, it would be a simple matter to create one. Simply override * for functors (boost::function<> for example) so that it returns a composite functor.
template < typename R1, typename R2, typename T1, typename T2 >
boost::function<R1(T2)> operator * (boost::function<R1(T2)> const& f, boost::function<R2(T2)> const& g)
{
return boost::bind(f, boost::bind(g, _1));
}
Untested, but I suspect it's close if it doesn't work out of the box.
Template them.
template<typename T1> class FunctorOne {
FunctorOne(T1 newt)
: t(newt) {}
void operator()() {
t();
}
T1 t;
};
template<> class FunctorOne<void> {
void operator()() {
}
};
template<typename T1> class FunctorTwo {
FunctorOne(T1 newt)
: t(newt) {}
void operator()() {
t();
}
T1 t;
};
template<> class FunctorTwo<void> {
void operator()() {
}
};
FunctorOne<FunctorTwo<FunctorOne<FunctorTwo<void>>>>> strangefunctionobject(FunctorTwo(FunctorOne(FunctorTwo()));
Excellent use of typedefs is recommended.
Edit: Whoops. Turns out that type inference in constructors sucks. I'll get back in a minute with something that actually works :P
Even more edit:
If you wanted just functors rather than functionoids, you could just create a new instance, or even just use static functions.
template<typename T1, typename T2> class FunctorOne {
public:
static bool Call() {
T1::Call(T2::Call());
return true;
}
};
template<> class FunctorOne<void, void> {
public:
static bool Call() {
}
};
template<typename T1> class FunctorTwo {
public:
static bool Call() {
T1::Call();
}
};
template<> class FunctorTwo<void> {
public:
static bool Call() {
}
};
bool haicakes = FunctorOne<FunctorTwo<void>, FunctorTwo<void>>::Call();
This assumes that in any given function, you can handle each different signature somewhat manually. Use of decltype could help in this regard with a C++0x compiler.
C++11. No boost. No helper classes. Any amount of arguments. Just std::function and variadic templates.
template <typename F1, typename F2>
struct function_composition_traits : public function_composition_traits<decltype(&F1::operator()), decltype(&F2::operator())>
{};
template <typename ClassType1, typename ReturnType1, typename... Args1, typename ClassType2, typename ReturnType2, typename... Args2>
struct function_composition_traits<ReturnType1(ClassType1::*)(Args1...) const, ReturnType2(ClassType2::*)(Args2...) const>
{
typedef std::function<ReturnType2(Args1...)> composition;
template <typename Func1, typename Func2>
inline static composition compose(const Func1& f1, const Func2& f2) {
return [f1,f2](Args1... args) -> ReturnType2 { return f2(f1(std::forward<Args1>(args)...)); };
}
};
template <typename F1, typename F2>
typename function_composition_traits<F1,F2>::composition compose(const F1& lambda1,const F2& lambda2)
{
return function_composition_traits<F1,F2>::template compose<F1,F2>(lambda1, lambda2);
}
template <typename F, typename... Fs>
auto compose(F f, Fs... fs) -> decltype(compose(f, compose(fs...)))
{
return compose(f, compose(std::forward<Fs>(fs)...));
}
Usage:
auto add = [](int x, int y){ return x+y; };
auto mul = [](int x){ return x*2; };
auto divide = [](int x) { return (double)x / 3.0; };
auto test = compose(add, mul, divide);
cout << "Result: " << test(2,3);
Output:
Result: 3.33333
See this answer https://stackoverflow.com/a/27727236/286335.
Really short, easy and general.