There is a common abstraction for both containers and functions. I learned it in Haskell, and I'm trying to implement it in C++.
Most C++ programmers are familiar with std::transform, roughly speaking given a function from type A to B, you can convert a container of type A to a container of type B.
You can transform functions in a similar way, given a function foo from A to B, you can convert a function bar taking Z to A to a function foo . bar taking Z to B. The implementation is simple, it's just composition.
I wanted to define a function fmap, on containers and functions, to reflect this abstraction for generic programming.
The container was easy (I know this isn't fully general)
template <typename A, typename Func>
auto fmap(Func f, vector<A> in) {
vector<decltype(f(in[0]))> out_terms{};
for(auto vec : in)
out_terms.push_back(f(vec));
return out_terms;
}
However, the analogous function for functions makes me much more nervous.
template <typename FuncT, typename Func>
auto fmap(FuncT f, Func in) {
return [f, in](auto x){
return f(in(x));
};
}
Although the template won't specialize for anything except callable things, I'm worried this will confuse overload resolution. I would like to introduce type constraints on the template parameters to restrict their resolution to function types to keep the name space clean. And I was going to ask how to do that.
This abstraction is extremely general, there are corresponding fmaps for pointers to values, which I suspect might conflict as well.
So I think my question is, can I have two different template implementations with the same template level signature? I'm almost certain the answer is no but maybe something similar can be faked. And if not, what tools are available today to distinguish between the overloads? Especially for function types.
This seems, to me, to be a textbook case for concepts, though I'm not sure.
Edit: Boost would be acceptable to use, and SFINAE in particular. I'm trying to find a solution that would be familiar to most programmers, and as convenient, and canonical as possible. I could rename fmap to compose, but then the programmer would have to know to pass compose to a template function accepting fmap. That would be unfortunate, because fmap is semantically unique.
Edit 2: A trivial example of how this is used.
template <typename T>
auto double_everything(T in){
auto doublef = [](auto x){return 2*x;};
return fmap(doublef, in);
}
It generalizes maps over containers to maps over "container like" things. So double_everything(vector<int> {1, 2, 3}) returns a vector with its elements doubled. But double_everything([](int x){ return x + 1; }) returns a function whose outputs are twice the outputs of the increment function. Which is like doubling a kind of list. The abstraction has some nice properties, I'm not just making it up. At any rate, renaming the function fmap to compose doesn't answer the question.
Edit 3:
fmap for a template C takes functions from A to B to functions from C<A> to C<B> and satisfies fmap( compose(f, g) , c ) = fmap( f, fmap( g, c )). This is a nice structure preserving property.
Functions which do this for ranges already exist by different names. But ranges aren't the only templates on types. Here is fmap for std::optional:
template<typename T, typename Func>
auto fmap(Func f, optional<T> o) -> optional<f(*o)>{
if(o)
return f(*o);
else
{};
}
This implementation doesn't involve any range concepts at all, like thefmap for functions presented earlier. But it satisfies the semantic requirements for fmap.
I'm trying to define fmap for different overloads in the same way I would define a new operator * for a custom matrix type. So I would happily define fmap in terms of boost::transform_iterator. Then these algorithms would work with a function generic in terms of fmap.
Here is an example of such a function:
template <
template<typename, typename> class Cont,
typename Fmappable,
typename Alloc,
typename Func>
auto map_one_deep(Func f, Cont<Fmappable, Alloc> c){
auto g = [f](Fmappable x){ return fmap(f, x); };
return fmap(g, c);
}
now if we write
auto lists = vector<vector<int> > { {1, 2, 3}, {4, 5, 6} };
auto lists_squared = map_one_deep( [](int x){return x*x;} , lists);
lists_squared printed gives
1 4 9
16 25 36
If we instead had a vector of optionals, the optionals would be squared provided they contained elements.
I'm trying to understand how one should work with higher order functions in c++.
You can fake it with SFINAE, but you shouldn't. It's a matter of style and idiom.
Haskell is all about type classes, with a programmer expecting to have to spangle each type with all the clubs it belongs to. C++, in contrast, wants to be more implicit in specifying a type's capabilities. You've shown "vector" and "arbitrary callable" there, but why just vector? Why not an arbitrary container type? And this arbitrary container type I just wrote has an operator(), because reasons. So which one should it choose?
Bottom line, while you can use SFINAE tricks to resolve technical ambiguities, you shouldn't use them to resolve essential ambiguities. Just use two different names.
Here's the simplest compromise I found
template <typename FuncT, typename O, typename T>
auto fmap(FuncT f, function<O(T)> in){
return [f, in](T x){
return f(in(x));
};
}
Unfortunately this requires that function<Output(Input)> decorate the call site, and it litters indirections. I'm pretty sure this is the best one can do if constraining fmap is required.
Edit: You can do better. The link gives a way to restrict to callables, that also in-lines.
The function could be written like this:
template <typename FuncT, typename T>
auto fmap(FuncT f, tagged_lambda<T> in){
return tag_lambda([f, in](T x){
return f(in(x));
});
}
You could choose the version you want at the call site, by calling
fmap(g, tag_lambda({}(int x){return x + 1;}) );
or
fmap(g, function<int(int)>({}(int x){return x + 1;}) );
Given how templates work, I'm pretty sure tagging the function is required.
Here is a blog post which also talks about the issue, and discusses other options.
http://yapb-soc.blogspot.com/2012/10/fmap-in-c.html.
Related
Consider following code:
int64_t signed_vector_size(const std::vector v){
return (int64_t)v.size();
}
This does not work since std::vector is a template. But my function works for every T!
Easy fix is to just do
1)
template<typename T>
int64_t signed_vector_size(const std::vector<T>& v){
return (int64_t)v.size();
}
or make the template implicit
2)
int64_t signed_vector_size(const auto& v){
return (int64_t)v.size();
}
Or concept based solution, option 3.
template<class, template<class...> class>
inline constexpr bool is_specialization = false;
template<template<class...> class T, class... Args>
inline constexpr bool is_specialization<T<Args...>, T> = true;
template<class T>
concept Vec = is_specialization<T, std::vector>;
int64_t signed_vector_size(const Vec auto& v){
return (int64_t)v.size();
}
I like the second solution, but it accepts any v, while I would like to limit it to the vector type only. Third is the best when just looking at the function, but specifying concepts is a relatively a lot of work.
Does C++20 syntax has any shorter way for me to specify that I want any std::vector as an argument or is the 1. solution the shortest we can do?
note: this is silly simplified example, please do not comment about how I am spending too much time to save typing 10 characters, or how I am sacrificing readability(that is my personal preference, I understand why some people like explicit template syntax).
A template is just a pattern for something. vector is the pattern; vector<int, std::allocator<int>> is a type. A function cannot take a pattern; it can only take a type. So a function has to provide an actual type.
So if you want a function which takes any instantiation of a template, then that function must itself be a template, and it must itself require everything that the template it takes as an argument requires. And this must be spelled out explicitly in the declaration of the function.
Even your is_specialization falls short, as it assumes that all template arguments are type arguments. It wouldn't work for std::array, since one of its arguments is a value, not a type.
C++ has no convenient mechanism to say what you're trying to say. You have to spell it out, or accept some less-than-ideal compromise.
Also, broadly speaking, it's probably not a good idea. If your function already must be a template, what would be the harm in taking any sized_range? Once you start expanding templates like this, you're going to find yourself less likely to be bound to specific types and more willing to accept any type that fulfills a particular concept.
That is, it's rare to have a function that is specific enough that it needs vector, but general enough that it doesn't have requirements on the value_type of that vector too.
Note that is not valid in standard C++20, but you can achieve exactly what you want with the following syntax that is supported by GCC as an extension.
std::vector<auto>
Which is shorthand for std::vector<T> where T is unconstrained.
http://coliru.stacked-crooked.com/a/6422d0284d299b85
How about this syntax?
int64_t signed_vector_size(const instance_of<std::vector> auto& v){
return (int64_t)v.size();
}
Basically we want to be able to say "this argument should be an instance of some template". So, say that?
template<template<class...>class Z, class T>
struct is_instance_of : std::false_type {};
template<template<class...>class Z, class...Ts>
struct is_instance_of<Z, Z<Ts...>> : std::true_type {};
template<class T, template<class...>class Z>
concept instance_of = is_instance_of<Z, T>::value;
int64_t signed_vector_size(const instance_of<std::vector> auto& v){
return (int64_t)v.size();
}
that should do it. Note that I don't make a Vec alias; you can pass in partial arguments to a concept. The type you are testing is prepended.
Live example.
Now, I'd actually say this is a bit of an anti-pattern. I mean, that size? Why shouldn't it work on non-vectors? Like, std::spans or std::deques.
Also, instance_of doesn't support std::array, as one of the arguments isn't a type. There is no way to treat type, template and value arguments uniformly in C++ at this point.
For each pattern of type, template and value arguments you'd need a different concept. Which is awkward.
When you are working with templates and with decltype you often need an instance of a certain type even though you do not have any the moment. In this case, std::declval<T>() is incredibly useful. This creates an imaginary instance of the type T.
Is there a something similar for concepts? i.e. a function which would create and imaginary type for a concept.
Let me give you an example(a bit contrived but should serve the purpose):
Let's define a concept Incrementable
template <typename T>
concept Incrementable = requires(T t){
{ ++t } -> T;
};
Now I would like to have a concept which tests if an object has the operator operator() which can accept Incrementable. In my imaginary syntax I would write something like this:
template <typename F, typename T = declval<Incrementable>>
concept OperatesOnIncrementable = requires(F f, T t){
{ f(t) } -> T;
}
There the declval in typename T = declval<Incrementable> would create an imaginary type T which is not really a concrete type but for all intents and purposes behaves like a type which satisfies Incrementable.
Is there a mechanism in the upcoming standard to allow for this? I would find this incredibly useful.
Edit: Some time ago I have asked a similar question if this can be done with boost::hana.
Edit: Why is this useful? For example if you want to write a function which composes two functions
template <typename F, typename G>
auto compose(F f, G g) {
return [f, g](Incrementable auto x) { return f(g(x)); };
}
I want to get an error when I try to compose two functions which cannot be composed. Without constraining the types F and G I get error only when I try to call the composed function.
There is no such mechanism.
Nor does this appear to be implementable/useful, since there is an unbounded number of Incrementable types, and F could reject a subset selected using an arbitrarily complex metaprogram. Thus, even if you could magically synthesize some unique type, you still have no guarantee that F operates on all Incrementable types.
Is there a something similar for concepts? i.e. a function which would create and imaginary type for a concept.
The term for this is an archetype. Coming up with archetypes would be a very valuable feature, and is critical for doing things like definition checking. From T.C.'s answer:
Thus, even if you could magically synthesize some unique type, you still have no guarantee that F operates on all Incrementable types.
The way to do that would be to synthesize an archetype that as minimally as possible meets the criteria of the concept. As he says, there is no archetype generation in C++20, and is seems impossible given the current incarnation of concepts.
Coming up with the correct archetype is incredibly difficult. For example, for
template <typename T>
concept Incrementable = requires(T t){
{ ++t } -> T;
};
It is tempting to write:
struct Incrementable_archetype {
Incrementable_archetype operator++();
};
But that is not "as minimal as possible" - this type is default constructible and copyable (not requirements that Incrementable imposes), and its operator++ returns exactly T, which is also not the requirement. So a really hardcore archetype would look like:
struct X {
X() = delete;
X(X const&) = delete;
X& operator=(X const&) = delete;
template <typename T> operator,(T&&) = delete;
struct Y {
operator X() &&;
};
Y operator++();
};
If your function works for X, then it probably works for all Incrementable types. If your function doesn't work for X, then you probably need to either change the implementation so it does or change the constraints to to allow more functionality.
For more, check out the Boost Concept Check Library which is quite old, but is very interesting to at least read the documentation.
There are a lot of examples on the web of using STL to pass in functions or function objects as parameters, for example in std::count .
How do I write my own functions that take such arguments?
As a simple example, say my class is:
struct Foo{
int val=0;
int methodinc()const{return val+1};
}
I would like to define a function funcall like:
int funcall (foo arg, function f)
{return f(arg); }
where the declaration “function” is what I am not sure of, among other things. The term “funcall” comes from Lisp, where (funcall f a b c) just applies f to the arguments a b c.
Then something like this should work:
Foo ff;
funcall(ff,Foo::methodinc); // should return 1
funcall(ff, [](Foo x) {return x.val+1;}) // should return 1
What are simple ways to accomplish this?
I am writing these as debugging helpers, the “funcall” would be used as part of the implementation of my own like my own data structure’s analogs of count, remove-if, transform and other like STL functions that take function arguments. But I do not want to write complicated template expressions to define my code.
The initial answers to this question suggest that the whole notion of declaring and using function arguments is a bit obscure, at least to me. Perhaps before addressing funcall, an even easier task might be just to pass a functional argument to another function, not use it. For example, in C++, to count a vector v I have to write
std::count(v.begin, v.end(), [](int j){return j>3})
How can one write a count that always counts the whole vector, so that:
mycount(v,[](int j){return j>3})
is the same as above? And could this "mycount" work for member function pointers instead of lambdas?
This question is basically the same as the "funcall" question but without the requirement actually to call the function object that is passed.
Typically a function template suits this sort of need for flexibility best:
template <typename F, typename T>
auto funcall(T && t, F f) -> decltype(f(std::forward<T>(t))
{
return f(std::forward<T>(t));
}
Instead of the trailing return type and decltype you can also use the result_of trait:
template <typename F, typename T>
typename std::result_of<F(T&&)>::type funcall(T && t, F f)
{
return f(std::forward<T>(t));
}
Or, in C++14, you can just say decltype(auto) funcall(T && t, F f) with no trailing return type, and it'll be deduced automatically.
The main reason for making F a deduced template argument rather than a fixed type (such as std::function<R(T)> is to allow you to call funcall directly with lambdas and bind/mem_fn expressions, which have unknowable types. Passing those directly allows efficient inlining opportunities, whereas creating of an std::function object is rather expensive by comparison.
C++ is an extraordinarily powerful and complex language. In it you can do anything you can do in Lisp, including implementing Lisp yourself. The problem is that to get there you will have to learn rather a lot about the language and what it can do. Using functions as objects is unfortunately one of the most complicated parts of C++.
There are multiple ways to solve your problem. The #Kerrek answer is an excellent one, but clearly beyond what you're ready for. The code provided in your edit is for a lambda, which will not necessarily make things simpler.
At its heart, function objects in C++ are just pointers. They look like this.
typedef int (*func)(int a, char b);
int f(int aa, char bb) {
return aa + bb;
}
int main(void) {
func fv = f;
int ret = fv(10, ' ');
printf ("ret=%d", ret);
return 0;
}
Here func is a type representing a function call, f is the actual function and fv is a functional call variable.
From this structure all else is built. With templates the compiler does the type matching and with lambdas you avoid having to think up nmes. Underneath it all, C/C++ functions are just pointers.
So the answer is that you can write your own functions that take functions as arguments when you know that those arguments are simply pointers to functions of a suitable type, declared as shown above.
I have been trying to implement in C++11 the function map from Python. It seems to work for any kind of callable objet, but I have to specify the template type parameter if I want it to work with function templates. Example:
#include <iostream>
#include <list>
template<typename T>
T abs(T x)
{
return x < 0 ? -x : x;
}
int main()
{
std::list<int> li = { -1, -2, -3, -4, -5 };
for (auto i: map(&abs<int>, li))
{
std::cout << i << std::endl;
}
}
It works fine, but I would like it to deduce the int parameter from the second argument of the function, and hence be able to write:
for (auto i: map(&abs, li))
{
std::cout << i << std::endl;
}
My map function is written as:
template<typename Callable, typename Container>
auto map(const Callable& function, Container&& iter)
-> MapObject<Callable, Container>
{
return { function, std::forward<Container>(iter) };
}
where MapObject is part of the implmentation and not a real problem here. How could I change its definition so that the template type of the Callable object can be deduced from the Container object? For example, how can map know that we have to use abs<int> for a given abs when a list<int> is given?
It works fine, but I would like it to deduce the int parameter from the second argument of the function, and hence be able to write:
for (auto i: map(&abs, li))
{
std::cout << i << std::endl;
}
The problem is that abs is not a function, but a function template, and thus there is no address-of abs, although there is &abs<int>, since abs<int> (specialization) is indeed a function (generated from a template).
Now the question is what you really want to solve, and in particular you must realize that C++ is a statically typed language where python is a dynamically typed language. It is unclear to me what you are trying to achieve here on different levels. For example, the function map in python has an equivalent in std::transform in C++:
a = [ 1, 2, 3 ]
a = map(lambda x: 2*x, a)
std::vector<int> v{1,2,3};
std::transform(v.begin(),v.end(),v.begin(),[](int x){ return 2*x; });
Where I have cheated slightly because in python it will create a different container yet in C++ transform works at the iterator level and knows of no container, but you can get the same effect similarly:
std::vector<int> v{1,2,3};
std::vector<int> result;
// optionally: result.reserve(v.size());
std::transform(v.begin(),v.end(),
std::back_inserter(result),
[](int x) { return 2*x; });
I'd advice that you learn the idioms in the language rather than trying to implement idioms from other languages...
BTW, if you are willing to have the user specify the type of the functor that is passed to the map function, then you can just pass the name of the template and let the compiler figure out what specialization you need:
template <typename Container>
auto map(Container && c,
typename Container::value_type (*f)(typename Container::value_type))
-> MapObject<Callable<T>,Container>;
template <typename T>
T abs(T value);
int main() {
std::vector<int> v{1,2,3,4};
map(v,abs);
}
This is less generic than what you were trying to do, as it only accepts function pointers and of concrete type (this is even less generic than std::transform) and it works as when the compiler sees abs (without the &) it will resolve it to the template, and thus to the set of specializations. It will then use the expected type to select one specialization and pass it in. The compiler will implicitly do &abs<int> for you in this case.
Another more generic alternative is not using functions, but functors. With this in mind you can define abs as:
struct abs {
template <typename T>
T operator()(T t) { ...}
};
And then pass a copy of the functor in instead of the function pointer. There is no need to determine the overload to be used where you pass the object abs into the map function, only when it is used. The caller side would look like:
for (auto& element : map(container,abs()))
Where the extra set of parenthesis is creating an object of type abs and passing it in.
Overall, I would try to avoid this. It is a fun thing to do, and you can probably get to a good solution, but it will be hard and require quite a bit of c++ expertise. Because it is not supported by the language, you will have to design something that works within the language and that requires compromises on different features or syntax. Knowing the options is a hard problem in itself, understanding the compromises even harder and getting to a good solution much harder. And the good solution will probably be worse than the equivalent idiomatic C++ code.
If you program in C++, program C++. Trying to code python through a C++ compiler will probably give you the pain of C++ and the performance of python.
It doesn't deduce it because you never specified that Callable is a template. You make Callable a template template parameter and it should deduce its type for you.
template<template <typename T> typename Callable, typename Container>
auto map(const Callable<T>& function, Container&& iter)
-> MapObject<Callable<T>, Container>
{
return { function, std::forward<Container>(iter) };
}
You might get bitten though as you can't take the address of a template still to be instantiated. Not sure why you need the address-of though...
I've just seen this really nice talk Rock Hard: C++ Evolving by Boris Jabes. In the section of the talk concerning Higher-Order Generic Programming he says that the following is an example of a function that is more generic with regards to its return type and leads to fewer template function overloads
template <typename Func>
auto deduce(const Func & f) -> decltype(f())
{..}
This however can be realized using plain template syntax as follows
template <typename Func>
Func deduce(const Func & f)
{..}
so I guess the example chosen doesn't really show the unique power of decltype. Can anyone give an example of such a more enlightening usage of decltype?
Your suspicions are incorrect.
void f() { }
Now deduce(&f) has type void, but with your rewrite, it has type void(*)(). In any case, everywhere you want to get the type of an expression or declaration, you use decltype (note the subtle difference in between these two. decltype(x) is not necessarily the same as decltype((x))).
For example, it's likely your Standard library implementation somewhere contains lines like
using size_t = decltype(sizeof(0));
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);
Finding out the correct return type of add has been a challenging problem throughout past C++. This is now an easy exercise.
template<typename A, typename B>
auto add(A const& a, B const& b) -> decltype(a + b) { return a + b; }
Little known is that you can use decltype before :: and in a pseudo destructor name
// has no effect
(0).~decltype(0)();
// it and ite will be iterators into an initializer list
auto x = { 1, 2, 3 };
decltype(x)::iterator it = x.begin(), ite = x.end();
std::for_each(c.begin(), c.end(), [](decltype (c.front()) val){val*=2;});
Autodeducting the value_type of the container c can't be done without decltype.
One place that I use it, is where I need to make a variable that must have same type of another variable . but I'm not sure if in future the type will stay same or not .
void foo(int a)//maybe in future type of a changed
{
decltype(a) b;
//do something with b
}