I have a program where I must print many STL vectors on the screen after doing some calculation on each component. So I tried to create a function like this:
template <typename a>
void printWith(vector<a> foo, a func(a)){
for_each(foo.begin(), foo.end(), [func](a x){cout << func(x) << " "; });
}
And then use it like this:
int main(){
vector<int> foo(4,0);
printWith(foo, [](int x) {return x + 1;});
return 0;
}
Unfortunately, I'm having a compiling error about the type of the lambda expression I've put inside the printWith call:
g++ -std=gnu++0x -Wall -c vectest.cpp -o vectest.o
vectest.cpp: In function ‘int main()’:
vectest.cpp:16:41: error: no matching function for call to ‘printWith(std::vector<int>&, main()::<lambda(int)>)’
vectest.cpp:10:6: note: candidate is: void printWith()
make: *** [vectest.o] Error 1
Of course, if I do:
int sumOne(int x) {return x+1;}
then printWith(foo, sumOne); works as intended. I thought the type of a lambda expression would be the type of a function with the inferred return type. I also though that I could fit a lambda anywhere I could fit a normal function. How do I make this work?
The following works for me:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename F>
void printWith(vector<a> foo, F f){
for_each(foo.begin(), foo.end(), [&](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
printWith(foo, [](int x) {return x + 1;});
std::cout << '\n';
return 0;
}
Testing:
$ g++-4.5 -std=gnu++0x -Wall test.cpp
$ ./a.out
2 3 4 5 6
Alternatively, you can exploit the fact that closure types with no lambda-capture can be implicitly converted to function pointers. This is closer to your original code and also cuts down on the number of instantiations of the function template (in the original solution you get a new instantiation every time you use the function template with a different function object type; note though that it doesn't matter much in this specific case since the printWith function is very short and most probably will be always inlined):
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename b>
void printWith(const vector<a>& foo, b f(a)){
for_each(foo.begin(), foo.end(), [=](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
printWith<int, int>(foo, [](int x) {return x + 1;});
std::cout << '\n';
return 0;
}
Unfortunately, implicit conversion doesn't play very well with template argument deduction: as you can see, I had to specify template arguments in the call to printWith.
Another alternative is to use std::function. This also helps to minimize the number of template instantiations and works even for lambda expressions with lambda-capture, but has the same problems with template argument deduction:
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
template <typename a, typename b>
void printWith(const vector<a>& foo, std::function<b(a)> f){
for_each(foo.begin(), foo.end(), [&](a x){cout << f(x) << " "; });
}
int main(){
vector<int> foo = {1,2,3,4,5};
int y = 1;
printWith<int, int>(foo, [&](int x) { return x + y; });
std::cout << '\n';
return 0;
}
The reason that you're having a problem is because you're trying to use a function. Free functions have a specific representation (as a function pointer) which is not interchangable with function objects of any kind. Function pointers (which is basically what you have here) should be avoided. You need to take a function object directly with it's type specified by template.
template <typename a, typename Func>
void printWith(vector<a> foo, Func func){
for_each(foo.begin(), foo.end(), [&](a x){cout << func(x) << " "; });
}
Alternatively, take a polymorphic function object such as std::function.
template<typename a>
void printWith(vector<a> foo, std::function<string(const a&)> func) {
for_each(foo.begin(), foo.end(), [&](a x) { cout << func(x) << " "; });
}
void printWith(vector<a> foo, b func(a)){
This is wrong, you can't do that and that makes the compiler not taking account of this code as it's not valid.
You have two ways to fix this :
1) don't ask for a parameter type, just ask for a functor:
void printWith(vector<a> foo, b func ){ // keep the rest of the code the same
The rest of your function will not compile if func don't take a a as parameter anyway.
2) force the functor type:
template <typename a>
void printWith(vector<a> foo, std::function< void (a) > func ){
Then it's like if you were using a function pointer. No (or less) compile-time optimization, but at least you enforce the functor signature. See std::function or boost::function for details.
The reason this doesn't work is that you're mixing template argument deduction with implicit conversions. If you get rid of deduction it works:
printWith<int>(foo, [](int x) {return x + 1;});
However, it would be better (inside printWith) to let func's type be another template parameter, as others recommend.
If on the other hand you really want to add constraints to this type there are better ways to do it using SFINAE (for soft errors) or static_assert (for hard errors).
For instance:
// A constraints metafunction
template<typename T, typename Element>
struct is_element_printer
: std::is_convertible<T, Element (*)(Element)>
{};
Here, is_element_printer<T, Element>::value is true iff T implicitly converts to Element (*)(Element). I'm only using this for illustrative purposes and I cannot recommend it for real use: there are plenty of things that could qualify as an 'element printer' in a lot of situations that are not function pointers. I'm only doing this because std::is_convertible is readily available from <type_traits> and there is no other more obvious test available. You should write your own.
Then:
template<typename Container, typename Functor>
void
printWith(Container&& container, Functor&& functor)
{
// avoid repetition
typedef typename std::decay<Container>::type::value_type value_type;
// Check our constraints here
static_assert(
std::is_element_printer<
typename std::decay<Functor>::type,
value_type
>::value,
"Descriptive error message here"
);
// A range-for is possible instead
std::for_each(container.cbegin(), container.cend(), [&functor](value_type const& v)
{ std::cout << functor(v) << ' '; });
}
Related
I am coming somewhat belatedly to Functional Programming, and getting my head around ranges/views. I'm using MSVC19 and compiling for C++ 20.
I'm using std::views::transform and the compiler doesn't seem to be inferring type as I might naively hope.
Here's a small example, which simply takes a vector of strings and computes their length:
#include <vector>
#include <iostream>
#include <ranges>
template<typename E>
auto length(const E& s)
{
std::cout << "Templated length()\n";
return static_cast<int>(s.length());
}
template<typename E>
auto getLengths(const std::vector<E>& v)
{
return v | std::views::transform(length<E>);
}
int main()
{
std::vector<std::string> vec = { "Larry","Curly","Moe" };
for (int i : getLengths(vec))
{
std::cout << i << "\n";
}
return 0;
}
with the output:
Templated length()
5
Templated length()
5
Templated length()
3
My question is why does changing the code in this line (dropping the <E>):
return v | std::views::transform(length);
give me an armful of errors, starting with: Error C2672 'operator __surrogate_func': no matching overloaded function found ?
Why doesn't the compiler infer that the type is std::string? If I replace the templates with a non-templated function:
auto length(const std::string& s) -> int
{
std::cout << "Specialized length()\n";
return static_cast<int>(s.length());
}
The code compiles and runs, so clearly without the template, the compiler finds a match for the particular type I am using.
This has nothing to do with views. You can reduce the problem to:
template <typename T>
int length(T const& x) { return x.length(); }
template <typename F>
void do_something(F&& f) {
// in theory use f to call something
}
void stuff() {
do_something(length); // error
}
C++ doesn't really do type inference. When you have do_something(length), we need to pick which length we're talking about right there. And we can't do that, so it's an error. There's no way for do_something to say "I want the instantiation of the function template that will be called with a std::string - it's entirely up to the caller to give do_something the right thing.
The same is true in the original example. length<E> is a concrete function. length is not something that you can just pass in.
The typical approach is to delay instantiation by wrapping your function template in a lambda:
void stuff() {
do_something([](auto const& e) { return length(e); }); // ok
}
Now, this works - because a lambda is an expression that has a type that can be deduced by do_something, while just length is not. And we don't have to manually provide the template parameter, which is error prone.
We can generalize this with a macro:
#define FWD(arg) static_cast<decltype(arg)&&>(arg)
#define LIFT(name) [&](auto&&... args) -> decltype(name(FWD(args)...)) { return name(FWD(args)...); }
void stuff() {
do_something(LIFT(length));
}
Which avoids some extra typing and probably makes the intent a little clearer.
Problem
I am trying to make a function which searches for a type in a parameter pack, then creates a lambda which invokes another function with that type as a template parameter e.g.:
auto fn = findType<MyType, SomeType, OtherType>("OtherType");
fn(otherFn) == otherFn<OtherType>();
I would like to write something like this:
template<class T, class ...Ts>
auto findType(const std::string& name) {
if (refl::is_reflectable<T>() && refl::reflect<T>().name == name) {
return []<class Fn>(Fn fn) {
fn<T>();
};
}
return findType<Ts...>(name);
}
However, C++ doesn't seem to recognise that fn could be parameterised with template types.
I am using gcc10 and C++20, so if possible, I can also use concepts.
I believe the problem can be summed up as: How can I pass a template-parameterised function into another function?
template<class C>
void fn() {}
template<class Fn, class Arg>
void mainFn(Fn fn) {
fn<Arg>(); // ???
}
Attempted searches
I had looked at template template parameters, but that seems to be only for templating types, not function calls.
I had also looked at C++ concepts, but std::invokable doesn't take in template parameters and requirements also don't seem to allow for such expressions:
return []<class Fn>(Fn fn) requires requires { fn<T>(); } {
Function parameters are variables. Not variable templates; just regular old variables. And a non-template variable cannot be given template parameters.
You cannot pass a function template anywhere. You can only pass a particular instantiation of a function template. The closest you can get to what you want is to pass a type that has a templated operator() overload, but unless you can provide the template parameters through deduction, the only way to invoke it is via fn.operator()<TemplateArguments>(params). So you may as well have given it a meaningful name.
The closest I can comeup with is to wrap the function template within class wrapper to achieve similar effect (Live):
#include <iostream>
using namespace std;
struct Fn
{
template <class Arg>
static void fn() {cout << "Fn::fn()\n";}
};
struct Gn
{
template <class Arg>
static void fn() { cout << "Gn::fn()\n"; }
};
template<class Arg, class F>
void mainFn(F dummy) {
F::template fn<Arg>();
}
int main()
{
mainFn<int>(Fn{});
mainFn<int>(Gn{});
}
outputs
Fn::fn()
Gn::fn()
I just wanted to put the closest I have gotten to what I wanted for others who may have special cases where this is possible.
As Nicol Bolas has already said, it is only possible through type deduction. So, if you have control over the function you receive, you can actually use that:
template<class C>
void fn(C* ignore) {}
template<class Fn, class Arg>
void mainFn(Fn fn) {
Arg* ignore = nullptr;
fn(ignore);
}
This removes the type parameter and makes use of type deduction to find the type.
In my case, this is insufficient as RedFog has mentioned that my findType function actually returns different types on the seemingly same call.
For C++, a practical way to go about passing a function to another function would be as follows:
#include <iostream>
#include <functional>
// To build and run the code
// g++ -std=c++20 -O3 -Wall -Werror -Wshadow -pedantic file.cpp -o file && ./file
double add5(double input_value) {
return input_value + 5;
}
template<typename T>
T add2(T input_value) {
return input_value + (T)2;
}
// std::function<double(double)> func
// return type ----^ ^---------------\
// list of `func` input argument types ---/
double func(double input_value, std::function<double(double)> func) {
return func(input_value);
}
int main() {
double value1 = 10.75;
double value2 = add2(value1);
std::cout << "Value1: " << value1 << std::endl;
std::cout << "Value2: " << value2 << std::endl;
// Add 5 to value2 by passing value2 and function 'add5' to function 'func'
double value3 = func(value2, &add5);
std::cout << "Value3: " << value3 << std::endl;
}
If you compile and run this code, the output should look like
Value1: 10.75
Value2: 12.75
Value3: 17.75
However, if you try to pass the template function (add2) to func, you will receive something along the lines of error: no matching function for call to 'func'. C++ does not allow you to pass template functions to other functions, BUT C++ does allow you to pass specific instances of template functions to other functions. If you replace
double value3 = func(value2, &add5);
with
double value3 = func(value2, &add2<double>);
at the bottom of main(), this will achieve the desired result.
Value1: 10.75
Value2: 12.75
Value3: 14.75
Unfortunately C++ does not allow you to pass a generalized template function to other functions at the moment.
Consider this code (which compiles on GCC and MSVC):
int main()
{
auto foo = [](auto p){
typedef decltype(p) p_t;
auto bar = [](){
return static_cast<p_t>(10);
};
return bar();
};
std::cout << foo(0ull) << std::endl;
}
foo() is a templated lambda because it has an auto parameter. But for bar() to know the type p_t, it must somehow be implicitly templated too, which then leads me to the question in the title:
Are all lambdas inside templated lambdas also templated lambdas?
If that's the case, then it seems like the number of templates parameters will grow pretty quickly if I have lots of nested lambdas (not necessarily a bad thing, but it comes as a surprise to me).
I'm not sure if you can actually say that a lambda is templated. The type of lambda with auto template parameter is not a template at all in the sense it does not match to template template parameter:
#include <iostream>
auto foo = [](auto param){};
template <class T>
struct functor_template {
void operator()() const { }
};
template <template <class...> class Foo, class... Ts>
void bar(Foo<Ts...>) {
}
int main() {
//bar(foo); //prog.cc:7:6: note: template argument deduction/substitution failed
bar(functor_template<int>{});
}
The reason for that is quite simple - only thing that is very close to be called template in such lambdas is their operator().
But I think you wanted to ask more if the type of lambda inside the lambda with auto parameter(s) is depended on parameters' types passed to that lambda. The answer is - yes. This can be easily tested:
#include <iostream>
#include <type_traits>
auto foo = [](auto p){
static_cast<void>(p);
typedef decltype(p) p_t;
auto bar = [](){
return static_cast<p_t>(10);
};
return bar;
};
int main() {
static_cast<void>(foo);
std::cout << std::is_same<decltype(foo(int{})), decltype(foo(float{}))>::value << std::endl;
std::cout << std::is_same<decltype(foo(int{})), decltype(foo(int{}))>::value << std::endl;
}
Output:
0
1
I was wondering if there is a lightweight version of std::function that works only for function pointers but doesnt have horrible :) syntax like regular function pointers.
Aka something like this:
int square(int x)
{
return x*x;
}
//...
function_ptr<int (int)> = square;
Ofc bind and all other fancy stuff std::function supports will fail, but I am ok with that, if I need std::function I will use it.
What you are asking for is for a template to tranform from signature to pointer to function to signature, that is, to add a pointer to the type. That is already done in the standard library:
std::add_pointer<X>::type
But since what you want is the nicer syntax, you can add a template alias:
template <typename T>
using ptr = typename std::add_pointer<T>::type;
Then you can use it directly in your container:
void f(int);
std::vector<ptr<void (int)>> v; // vector of pointers to functions taking `int`
v.push_back(&f);
Depending on the context you want to use this in, it could be as simple as auto and/or decltype:
#include <iostream>
int main()
{
auto f = square;
std::cout << f(5) << std::endl;
// define a type
using F = decltype(&square);
F g = square;
std::cout << g(5) << std::endl;
}
You can write an opaque wrapper if you do not want to use typedef directly. A prototype implementation using variadic templates is as follows. The same technique can be extended to other callable objects such as lambdas.
#include <iostream>
template<typename T>
struct function_ptr {};
template<class R, class... Args>
struct function_ptr<R(Args...)>{
typedef R (*funcType)(Args...);
function_ptr(funcType f) : _f(f) {}
funcType _f;
R operator()(Args... args) { return _f(args...);}
};
int square(int x) {
return x*x;
}
int main() {
function_ptr<int (int)> f = square;
std::cout << f(2) << std::endl;
}
Given a callable object ( a function ) a, and an argument b ( or a series of arguments ), I would like to deduce the type returned from f considering that f is overloaded with multiple signatures.
one of my many attempts is
#include <iostream>
#include <cstdint>
#include <string>
#include <functional>
#include <utility>
#include <typeinfo>
int foo(uint32_t a) { return ((a + 0) * 2); }
bool foo(std::string a) { return (a.empty()); }
/*template <typename A, typename B> auto bar(A a, B b) -> decltype(a(b)) {
return (a(b));
}*/
/*template <typename A, typename B> decltype(std::declval<a(b)>()) bar(A a, B b)
{
return (a(b));
}*/
template <typename A, typename B> void bar(std::function<A(B)> a, B b) {
std::cout << a(b) << "\n";
}
int main() {
// the following 2 lines are trivial and they are working as expected
std::cout << foo(33) << "\n";
std::cout << typeid(decltype(foo(std::string("nothing")))).name() << "\n";
std::cout << bar(foo, 33) << "\n";
//std::cout << bar(foo, std::string("Heinz")) << "\n";
return (0);
}
and 2 templates options are commented out and included in the previous code.
I'm using declval result_of auto decltype without any luck.
How does the overloading resolution process works at compile time ?
If anyone wants to know why I'm trying to get creative with this, is that I'm trying to implement some Currying in C++11 in a workable/neat way.
The problem is that you can't easily create a function object from an overload set: when you state foo or &foo (the function decays into a function pointer in most case, I think) you don't get an object but you get an overload set. You can tell the compiler which overload you want by either calling it or providing its signature. As far as I can tell, you don't want either.
The only approach I'm aware of is to turn your function into an actual function object which makes the problem go away:
struct foo_object
{
template <typename... Args>
auto operator()(Args&&... args) -> decltype(foo(std::forward<Args>(args)...)) {
return foo(std::forward<Args>(args)...);
}
};
With that wrapper which is unfortunately needed for each name, you can trivially deduce the return type, e.g.:
template <typename Func, typename... Args>
auto bar(Func func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) {
// do something interesting
return func(std::forward<Args>(args)...);
}
int main() {
bar(foo_object(), 17);
bar(foo_object(), "hello");
}
It doesn't quite solve the problem of dealing with overload sets but it gets reasonably close. I experimented with this idea, essentially also for the purpose of currying in the context of an improved system of standard library algorithms and I'm leaning towards the algorithms actually being function objects rather than functions (this is desirable for various other reasons, too; e.g., you don't need to faff about when you want to customize on algorithm with another one).
If foo is overloaded, you need to use the following:
#include <type_traits>
int foo(int);
float foo(float);
int main() {
static_assert(std::is_same<decltype(foo(std::declval<int>())), int>::value, "Nope.");
static_assert(std::is_same<decltype(foo(std::declval<float>())), float>::value, "Nope2.");
}
If it's not, then this will suffice:
#include <type_traits>
bool bar(int);
int main() {
static_assert(std::is_same<std::result_of<decltype(bar)&(int)>::type, bool>::value, "Nope3.");
}
Yes, it is verbose because you're trying to explicitly extract what implicit ad-hoc overloading does for you.
This is actually already implemented for you std::result_of. Here is a possible implementation
template<class>
struct result_of;
// C++11 implementation, does not satisfy C++14 requirements
template<class F, class... ArgTypes>
struct result_of<F(ArgTypes...)>
{
typedef decltype(
std::declval<F>()(std::declval<ArgTypes>()...)
) type;
};