Are all lambdas inside templated lambdas also templated lambdas? - c++

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

Related

Approaches to function SFINAE in C++

I am using function SFINAE heavily in a project and am not sure if there are any differences between the following two approaches (other than style):
#include <cstdlib>
#include <type_traits>
#include <iostream>
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo()
{
std::cout << "method 1" << std::endl;
}
template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0>
void foo()
{
std::cout << "method 2" << std::endl;
}
int main()
{
foo<int>();
foo<double>();
std::cout << "Done...";
std::getchar();
return EXIT_SUCCESS;
}
The program output is as expected:
method 1
method 2
Done...
I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Are there any circumstances when these two approaches differ?
I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Suggestion: prefer method 2.
Both methods work with single functions. The problem arises when you have more than a function, with the same signature, and you want enable only one function of the set.
Suppose that you want enable foo(), version 1, when bar<T>() (pretend it's a constexpr function) is true, and foo(), version 2, when bar<T>() is false.
With
template <typename T, typename = std::enable_if_t<true == bar<T>()>>
void foo () // version 1
{ }
template <typename T, typename = std::enable_if_t<false == bar<T>()>>
void foo () // version 2
{ }
you get a compilation error because you have an ambiguity: two foo() functions with the same signature (a default template parameter doesn't change the signature).
But the following solution
template <typename T, std::enable_if_t<true == bar<T>(), bool> = true>
void foo () // version 1
{ }
template <typename T, std::enable_if_t<false == bar<T>(), bool> = true>
void foo () // version 2
{ }
works, because SFINAE modify the signature of the functions.
Unrelated observation: there is also a third method: enable/disable the return type (except for class/struct constructors, obviously)
template <typename T>
std::enable_if_t<true == bar<T>()> foo () // version 1
{ }
template <typename T>
std::enable_if_t<false == bar<T>()> foo () // version 2
{ }
As method 2, method 3 is compatible with selection of alternative functions with same signature.
In addition to max66's answer, another reason to prefer method 2 is that with method 1, you can (accidentally) pass an explicit type parameter as the second template argument and defeat the SFINAE mechanism completely. This could happen as a typo, copy/paste error, or as an oversight in a larger template mechanism.
#include <cstdlib>
#include <type_traits>
#include <iostream>
// NOTE: foo should only accept T=int
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo(){
std::cout << "method 1" << std::endl;
}
int main(){
// works fine
foo<int>();
// ERROR: subsitution failure, as expected
// foo<double>();
// Oops! also works, even though T != int :(
foo<double, double>();
return 0;
}
Live demo here

Using a templated function as template parameter

I'm writing a class with a function that is repeatedly called and decided to implement this as giving the function as template parameter.
As a concrete example of what I'm talking about, consider the following class:
#include <array>
template<double (*func)(std::array<double,3>)>
class MyClass
{
public:
MyClass()
{
std::array<double,3> v {{0.1,0.2,0.1}};
func(v);
}
};
which can then be instantiated with a function, as for example:
double func(std::array<double,3> x)
{
return x[0]*x[0]+x[1];
}
int main()
{
MyClass<func> entity;
}
However, I need the function to be callable with different types (the operations in the function are of course applicable to all of them), that is I want to have this function templated, as in:
template<typename scalartype, typename vectype>
scalartype func1(vectype x)
{
scalartype res = x[0]*x[0]+x[1];
return res;
}
I can still use this as template parameter, but the function parameter and return type are then fixed in the class. So how can I have the function as templated function available in the class? Such that I can, for example, call it with an std::vector of four integers and have an integer returned.
I tried using template template parameters, but I can't even figure out how to use two template parameters with them (as they only seem to allow the template ... syntax). I'm sorry if this is formulated unclearly, I am still a newcomer.
You can put your template function in a class, and then pass in that class to MyClass.
#include <iostream>
#include <vector>
#include <array>
struct templateHolder {
template <typename vectype, typename scalartype = typename vectype::value_type>
static scalartype func(vectype x) {
return x[0] + x[1];
}
};
template<typename T>
class MyClass
{
public:
MyClass()
{
std::vector<int> vec {1,2};
std::cout << T::func(vec) << std::endl;
std::array<double, 2> arr {0.5, 3.33};
std::cout << T::func(arr) << std::endl;
}
};
int main() {
MyClass<templateHolder> foo;
return 0;
}
I chose to deduce scalartype from vectype. Not necessarily what you want but it could be an option depending on your use-case.

Neat way to parametrize function template with generic function pointer

Consider following case: I have
int bar1();
double bar2();
I want:
foo<bar1>(); // calls bar1, then uses its result.
foo<bar2>(); // calls bar2, then uses its result.
Naive way to write template foo() is to use additional parameter:
template <typename T, T (*f)()> void foo () {
// call f, do something with result
}
This works, but I need to do ugly syntax:
foo<decltype(bar1()), bar1>(); // calls bar1, then uses its result
I want to write something pretty, like above, just foo<bar1>.
P.S. Please do not recommend to accept argument at runtime. I need compile time parametrization with function pointer only.
P.S. Sorry forget to mention: I am looking for C++14 solution. C++17 appreciated and I upvoted answer with C++17 solution, but project now builds with C++14 and I can not change it in nearest future.
In order to get
foo<bar1>();
You need template<auto> from C++17. That would look like
int bar1() { return 1; }
double bar2() { return 2.0; }
template<auto function> void foo() { std::cout << function() << "\n"; }
int main()
{
foo<bar1>();
foo<bar2>();
}
Which outputs
1
2
Live Example
Before C++17 you have to specify the type as there is no auto deduction of the type of a non type template parameters.
So, I'll try to give the best possible answer that I'm aware of in 14. Basically a good approach (IMHO) to this problem is to "lift" the function pointer into a lambda. This allows you to write foo in the much more idiomatic way of accepting a callable:
template <class F>
void foo(F f);
You still get optimal performance, because the type of the lambda is unique, and so it gets inlined. You can more easily use foo with other things though. So now we have to turn our function pointer into a lambda that is hardcoded to call it. The best we can on that front is drawn from this question: Function to Lambda.
template <class T>
struct makeLambdaHelper;
template <class R, class ... Args>
struct makeLambdaHelper<R(*)(Args...)>
{
template <void(*F)(Args...)>
static auto make() {
return [] (Args ... args) {
return F(std::forward<Args>(args)...);
};
}
};
We use it like this:
auto lam = makeLambdaHelper<decltype(&f)>::make<f>();
To avoid having to mention it twice, we can use a macro:
#define FUNC_TO_LAMBDA(f) makeLambdaHelper<decltype(&f)>::make<f>()
You could then do:
foo(FUNC_TO_LAMBDA(bar1));
Live example: http://coliru.stacked-crooked.com/a/823c6b6432522b8b
I am looking for C++14 solution. C++17 appreciated and I upvoted answer with C++17 solution, but project now builds with C++14 and I can not change it in nearest future.
Unfortunately what you ask works starting from C++17.
If you want use the exactly syntax
foo<bar1>();
I don't thinks it's possible in C++14.
But, if you accept a little different syntax... I know that macros are distilled evil but... if you accept to call foo() as
FOO(bar1)();
you can define the macro
#define FOO(f) foo<decltype(f()), f>
A full working example
#include <iostream>
#define FOO(f) foo<decltype(f()), f>
int bar1 ()
{ std::cout << "bar1()" << std::endl; return 0; }
double bar2 ()
{ std::cout << "bar2()" << std::endl; return 1.0; }
template <typename T, T (*f)()>
void foo ()
{ f(); }
int main()
{
FOO(bar1)(); // print bar1()
FOO(bar2)(); // print bar2()
}
OK, so you asked specifically for bar1 and bar2 to be functions, but if you were willing to relax that constraint and instead allow them to be classes having a static member function that implements the desired behavior you could do it in the following way, which doesn't even require C++11 -
struct bar1 {
static int f() { return 42; }
};
struct bar2 {
static double f() { return 3.14159; }
};
template<typename bar>
void foo()
{
double x = bar::f();
std::cout << x << std::endl;
}
int main(int argc, char* const argv[])
{
foo<bar1>();
foo<bar2>();
}
How about this?
template<typename F>
auto foo(F* f)
{
return f();
}
int bar() { return 1; }
int main()
{
return foo(bar);
}

Is there in iso or boost function pointer that has the same syntax as std::function

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;
}

A problem with higher order functions and lambdas in C++0x

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) << ' '; });
}