Inline lambda expression causes compiler error - c++

template <typename T, typename Y, typename... Args>
class Bar
{
T& t;
public:
Bar(T& t) : t(t) { }
};
template <typename T, typename... Args>
void Foo(T &function) { new Bar<T, void, Args...>(function); }
int main()
{
auto foo = [] { };
Foo(foo); // ok
Foo([] { }); // fails (tested on GCC 4.5.3)
}
Why does it only fail when the lambda expression is written inline as an argument to Foo?

template <typename T, typename... Args>
void Foo(T &function) { new Bar<T, void, Args...>(function); }
Foo([] { }); // fails (tested on GCC 4.5.3)
Lambda is temporary. Don't try bind temporary to reference. Use value, or const-reference or rvalue-reference.

Related

Is it possible to call a function with all arguments default constructed?

Is it possible to have a function like std::invoke, but this function calls all arguments of the given function automatically with the default constructed types?
#include <iostream>
#include <functional>
// e.g. for a single arg
struct Test{
void operator()(int i) {
std::cout << std::to_string(i) << "\n";
}
};
int main(){
Test test;
std::invoke(test, {}); // this doesn't work, would like it to call with default constructed int (0).
return 0;
}
I would like something like
int main()
{
Test test;
invoke_with_defaults(test); // prints 0
return 0;
}
You need a class with a templated conversion operator, returning {} for any type:
struct DefaultConstruct
{
DefaultConstruct() = default;
DefaultConstruct(const DefaultConstruct &) = delete;
DefaultConstruct &operator=(const DefaultConstruct &) = delete;
template <typename T> operator T() && {return {};}
};
int main()
{
Test test;
std::invoke(test, DefaultConstruct{});
}
It's then possible to write a template that automatically determines how many of those have to be passed:
template <typename F, typename ...P>
decltype(auto) InvokeDefault(F &&func)
{
if constexpr (std::is_invocable_v<F, P...>)
return std::invoke(std::forward<F>(func), P{}...);
else
return InvokeDefault<F, P..., DefaultConstruct>(std::forward<F>(func));
}
int main()
{
Test test;
InvokeDefault(test);
}
And if the argument isn't callable at all, you get a compilation error after exceeding some implementation-defined limit (on Clang I got up to 256).
Initializer lists like {} cannot be forwarded as a parameter due not work due to language restrictions.
But you can mimick {} by wrapping it into a Defaulter class which can be passed around:
#include <iostream>
#include <functional>
// e.g. for a single arg
struct Test{
void operator()(int i) {
std::cout << std::to_string(i) << "\n";
}
};
struct Defaulter{
template<typename T>
operator T(){
return {};
}
};
int main(){
Test test;
std::invoke(test, Defaulter{});
return 0;
}
You could use something like this to create a tuple of all of the argument types, and then pass a default constructed instance of it to std::apply. The specialisation list would need to be quite long though to cover all of the const, volatile, noexcept, and ref-qualified variants though, and of course it cannot work with template or overloaded functions.
Eg:
template <typename T>
struct arg_extractor : arg_extractor<decltype(&T::operator())> {
};
template <typename R, typename... Args>
struct arg_extractor<R (*)(Args...)> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...)> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) const> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) noexcept> {
using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) const noexcept> {
using type = std::tuple<R, Args...>;
};
// All the rest...
template <typename T>
using arg_extractor_t = typename arg_extractor<T>::type;

For each type, call a template function with each of these types

As the title says, I'm trying to create something to be used as followed :
template <typename T>
void testFunc(int& i)
{
...
}
int i { 0 };
ForEach<int, float>::run<testFunc>(i);
I've already tried some things, but I'm hitting some problems:
template<typename CurrentComponentType, typename... ComponentTypes>
struct ForEach
{
template<void (&func)(auto&&... args)>
static constexpr void run(auto&&... args)
{
func<CurrentComponentType>(std::forward<decltype(args)>(args)...);
ForEach<ComponentTypes...>::run<func>(std::forward<decltype(args)>(args)...);
}
};
template<typename CurrentComponentType>
struct ForEach<CurrentComponentType>
{
template<void (&func)(auto&&... args)>
static constexpr void run(auto&&... args)
{
func<CurrentComponentType>(std::forward<decltype(args)>(args)...);
}
};
I don't know how to take a template function as a (template but not necessarily) argument.
For some reasons that I don't understand, I cannot call again the run() function as so: run<func>(. It says '<unresolved overloaded function type>'.
I think there are multiple things I don't understand.
How can I fix it, and why doesn't it work this way? What am I misunderstanding?
Each of the solutions below can be used like so:
int main(void)
{
int i { 0 };
ForEach<int, float>::run<testFunc>(i);
}
Because you can't pass an uninstantiated template function as a (template) parameter, you need to make it a template class with an operator():
#include <utility>
template<typename T>
struct testFunc
{
void operator()(int& i) {}
};
template<typename T, typename... Ts>
struct ForEach
{
template<template<typename> typename F, typename... Args>
static constexpr void run(Args&&... args)
{
ForEach<T>::template run<F>(std::forward<Args>(args)...);
ForEach<Ts...>::template run<F>(std::forward<Args>(args)...);
}
};
template<typename T>
struct ForEach<T>
{
template<template<typename> typename F, typename... Args>
static constexpr void run(Args&&... args)
{
F<T>{}(std::forward<Args>(args)...);
}
};
Starting in C++17, you can use fold expressions to avoid recursion:
#include <utility>
template<typename T>
struct testFunc
{
void operator()(int& i) {}
};
template<typename... Ts>
struct ForEach
{
template<template<typename> typename F, typename... Args>
static constexpr void run(Args&&... args)
{
(F<Ts>{}(std::forward<Args>(args)...), ...);
}
};
Finally, in C++20 you also have the option to use a lambda with a template parameter list instead:
#include <utility>
auto testFunc = []<typename T>(int& i) {};
template<typename... Ts>
struct ForEach
{
template<auto F, typename... Args>
static constexpr void run(Args&&... args)
{
(F.template operator()<Ts>(std::forward<Args>(args)...), ...);
}
};

Passing lambdas as template parameters: what type is actually deduced?

If I pass a lambda as a template parameter, what is the actual type of that parameter that is deduced? I have looked on the VS2017 debugger and the type of this lambda: [](int x) {return x; } is filename::__I2::int<lambda>(int).
The reason I am asking this is because I want to pass a lambda and then create an internal std::function from this. Note that this relates to this answer and why we have to use CTAD to construct an internal std::function instead of just passing the template parameter to a std::function.
As an example, I would like to do something like the following:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<Func> internalFunc = f; //this does not work
}
//usage
createStdFunc([](int x) {return x; }, 5);
However, this does not work, and I get the error 'initialising' cannot convert from 'Func' to 'std::function<Func>'. I am not sure how the types differ and how they have changed from passing into the function to initialising the std::function. Please note that I do know you can use CTAD from 2017 onwards, but was wondering what a solution for 2014 and before would have been?
In C++14 you can use return type deduction to figure out function signature, this implies that types of arguments passed into createStdFunc match:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<std::result_of_t<Func(Args...)> (Args...)> internalFunc{f}; //this does work
}
My way
#include <iostream>
#include <functional>
template <typename R, typename T, typename ... As>
constexpr std::function<R(As...)> getFuncType (R(T::*)(As...) const);
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
decltype(getFuncType(&F::operator())) internalFunc { f };
internalFunc(as...);
}
int main ()
{
createStdFunc([](int x) { std::cout << x << std::endl; }, 5);
}
Maybe also through a using
template <typename F>
using funcType = decltype(getFuncType(&F::operator()));
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
funcType<F> internalFunc { f };
internalFunc(as...);
}
The problem inside your code is that Func is not a function type. It's the type of the lambda. Lambdas compile down to something like this:
// equivalent:
// auto my_lambda = [](int v){ return v; };
struct /* unnamed */ {
auto operator()(int v) const { return v; }
} my_lambda;
The solution would be to extract the type of the operator() from the closure type:
using my_lambda_t = decltype(my_lambda);
// type: int(my_lambda_t::*)(int) const;
auto call_operator = &decltype(my_lambda_t)::operator();
Then, from the type of the operator(), you can deduce the type of the arguments and the return type:
template<typename>
struct extract_types {};
template<typename R, typename C, typename... Args>
struct extract_types<R(C::*)(Args...) const> {
using result = R;
using args_types = std::tuple<Args...>;
};
Generalized versions of this pattern is shipped in Boost.CallableTraits
You can write a simple trait to generalize callable types. If you handle both function pointers and anything with operator() (both const and non-const) you should be able to cover most use cases.
#include <tuple>
// For callable types
template<class T>
struct func_type : func_type<decltype(&T::operator())>{};
// For callable types' member functions (including `operator()`)
template<class T, class R, class ... Args >
struct func_type<R (T::*)(Args...) const> : func_type<R(*)(Args...)> {};
// For function pointers
template<class R, class ... Args >
struct func_type<R (*)(Args...)> {
using type = R(Args...);
using result = R;
using args = std::tuple<Args...>;
};
template<class T>
using func_type_t = typename func_type<T>::type;
func_type_t<T> should then give you a function type for most callable types T. Example uses :
#include <functional>
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
// Replaced `Func` with `func_type_t<Func>`
std::function<func_type_t<Func>> internalFunc = f;
}
int foo(int x) { return x; }
struct bar {
int operator()(int x) { return x; };
};
int main()
{
// With lambda expression
createStdFunc([](int x) {return x; }, 5);
// With function pointer
createStdFunc(foo, 5);
// With std::function
std::function<int(int)> std_func = [](int x) {return x; };
createStdFunc(std_func, 5);
// With a functor
createStdFunc(bar{}, 5);
}
The std::function template expects as its argument a function type from which it infers the return and parameter type for the callable to wrap. The closure type of a lambda expression is a callable, but it's not a function type.
C++17 introduced deduction guides for std::function which allow the correct type to be deduced from any callable argument. Pre C++17, you could use a set of helper templates to deduce the correct type, for example:
template <typename F>
struct deduce_func_type_helper;
template <typename R, typename... Args>
struct deduce_func_type_helper<R(&)(Args...)>
{
using type = std::function<R(Args...)>;
};
template <typename R, typename... Args>
struct deduce_func_type_helper<R(*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) const> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) volatile> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename F>
struct deduce_func_type_helper<F&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper<F&&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper : deduce_func_type_helper<decltype(&F::operator())> {};
template <typename F>
using func_type_t = typename deduce_func_type_helper<F>::type;
live example here
Note that above example is not complete; it's missing some specializations, e.g., for all possible combinations of const, volatile, and different ref qualifiers. So this can get quite verbose, you will probably want to go with C++17 if you can…

Variadic C++ Templates Termination After Unpack?

I'm trying to use C++ variadic templates to unpack a list of arguments of variable type, how would I remove the "T" object in the following artificial example:
struct Test
{
template <typename T, typename... Args>
void foo(T t, int i, Args... args) { foo(t, args...); }
template <typename T, typename... Args>
void foo(T t, double d, Args... args) { foo(t, args...); }
template <typename T>
void foo(T t) { }
};
struct DummyObject { };
and then executed like this:
DummyObject dummy;
Test test;
test.foo(dummy, 4, 5.0, 6, 7.0, 8.0, 9);
I'd like to remove the need to pass in the "dummy" object at all, I just can't figure out what the final "foo" function should look like in this case.
Let me flesh out your sample slightly:
struct Test
{
template <typename T, typename... Args>
void foo(T t, int i, Args... args) { doIThing(i); foo(t, args...); }
template <typename T, typename... Args>
void foo(T t, double d, Args... args) { doDThing(d); foo(t, args...); }
template <typename T>
void foo(T t) { }
};
So there's the two functions that do actual work: doIThing and doDThing. You got it 99% right, just... remove T.
struct Test
{
template <typename... Args>
void foo(int i, Args... args) { doIThing(i); foo(args...); }
template <typename... Args>
void foo(double d, Args... args) { doDThing(d); foo(args...); }
void foo() { }
};
Running here: http://coliru.stacked-crooked.com/a/b35ac716cf2960b3
Other method is to remove recursive call and have something like:
struct Test
{
template <typename... Args>
void foos(Args... args)
{
(foo(args), ...); // C++17 fold expression
#if 0 // C++11 or C++14
const int dummy[] = {0, (foo(args), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable
#endif
}
void foo(int t) { /*...*/ }
void foo(double t) { /*...*/ }
template <typename t> void foo(T t) { /**/ }
};
And then use it:
Test test;
test.foos(4, 5.0, 6, 7.0, 8.0, 9);

Binding function arguments in C++11

I'd like to generically "pickle" function calls so they can be executed later. The return type of those functions will always be void (for now). Something like this:
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(F, args...);
}
The problem is, if args contains a const reference, std::bind tries to copy construct the value, which is not always desired or even valid if the type lacks a copy constructor. How do I forward the arguments in a way that uses std::ref for lvalue references and the normal std::forward for lvalue references?
Example
#include <functional>
class NonCopyable {
public:
NonCopyable() {}
NonCopyable(const NonCopyable&) = delete;
};
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args)
{
return std::bind(function, std::forward<Args>(args)...);
}
int main()
{
NonCopyable obj;
auto f = pickle(
[](const NonCopyable&) {},
obj
);
return 0;
}
The above snippet won't compile, complaining about the deleted copy constructor. (I used forward here because someone suggested it, but has since deleted their answer, it seems).
Overloading, yay.
// also does the correct thing for `T const`
template<class T>
std::reference_wrapper<T> maybe_ref(T& v, int){ return std::ref(v); }
// just forward rvalues along
template<class T>
T&& maybe_ref(T&& v, long){ return std::forward<T>(v); }
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(function, maybe_ref(std::forward<Args>(args), 0)...);
}
The int/long parameters and 0 argument disambiguate the lvalue case for compilers that find the overloads to be ambiguous, and doesn't do any harm otherwise.
This is a bit ugly (overuse of enable_if), but it works:
template<typename T> typename std::enable_if<
!std::is_lvalue_reference<T>::value, T &&>::type
forward_as_ref(typename std::remove_reference<T>::type &t) {
return static_cast<T &&>(t);
}
template<typename T> typename std::enable_if<
!std::is_lvalue_reference<T>::value, T &&>::type
forward_as_ref(typename std::remove_reference<T>::type &&t) {
return t;
}
template<typename T> typename std::enable_if<
std::is_lvalue_reference<T>::value,
std::reference_wrapper<typename std::remove_reference<T>::type>>::type
forward_as_ref(T t) {
return t;
}
Here's a version using class template specialization instead:
template<typename T> struct forward_as_ref_type {
typedef T &&type;
};
template<typename T> struct forward_as_ref_type<T &> {
typedef std::reference_wrapper<T> type;
};
template<typename T> typename forward_as_ref_type<T>::type forward_as_ref(
typename std::remove_reference<T>::type &t) {
return static_cast<typename forward_as_ref_type<T>::type>(t);
}
template<typename T> T &&forward_as_ref(
typename std::remove_reference<T>::type &&t) {
return t;
}