I know about ADL and the swap idiom:
using std::swap;
swap(x, y);
boost::swap() does the above for you. Now, I want to push it further. Specifically, Have the swap perform x.swap(y) if possible, and fallback to boost::swap() otherwise. So, you don't have to implement both a member swap and a free one, which is verbose and redundant. I tried to implement such a swap and ended up with the following. Implementing things like this can become quite tricky. So, I'm wondering whether there is any flaws in my implementation, or if more succinct implementations exist.
#include <algorithm>
#include <utility>
namespace cppu_detail_swap {
template <typename T>
void swap_impl(T& x, T& y) {
using std::swap;
swap(x, y);
}
} // namespace cppu_detail_swap
namespace cppu {
namespace detail {
template <typename T>
void swap(T& x, T& y, int) {
cppu_detail_swap::swap_impl(x, y);
}
template <typename T>
auto swap(T& x, T& y, char) -> decltype(x.swap(y)) {
return x.swap(y);
}
} // namespace detail
template <typename T>
void swap(T& x, T& y) {
detail::swap(x, y, ' ');
}
} // namespace cppu
Your current solution is flawed for objects from the cppu namespace, e.g.
// [insert your code here]
namespace cppu
{
struct X{};
struct Y{ void swap(Y& y) { }; };
}
int main()
{
auto x1 = cppu::X{};
auto x2 = cppu::X{};
swap(x1, x2);
auto y1 = cppu::Y{};
auto y2 = cppu::Y{};
swap(y1, y2);
}
g++ tells me:
taste.cpp:9:7: error: call of overloaded ‘swap(cppu::X&, cppu::X&)’ is ambiguous
To get rid of this, you need to explicitly call std::swap in swap_impl, which is OK, since you arrived here through the cppu::swap implementation already. But then you do not use overloads for other types. Thus, I think you need to distinguish three cases:
Has own swap member function
Has no swap member function and is from namespace cppu
Has no swap member function and is any other namespace (here you need to use the ADL swap idiom).
Also, I concur with #Yakk that I would be more direct instead of using the int/char hack.
So let's go for it:
A helper for checking the availability of the swap member:
namespace cppu
{
namespace detail
{
template <typename T>
using void_t = void;
template <typename T, typename = void>
struct has_member_swap
{
static constexpr bool value = false;
};
template <typename T>
struct has_member_swap<
T,
void_t<decltype(std::declval<T&>().swap(std::declval<T&>()))>>
{
static constexpr bool value = true;
};
}
}
And a helper to check if T is from namespace cppu, see also here:
namespace helper
{
template <typename T, typename = void>
struct is_member_of_cppu : std::false_type
{
};
template <typename T>
struct is_member_of_cppu<
T,
decltype(adl_is_member_of_cppu(std::declval<T>()))> : std::true_type
{
};
}
namespace cppu
{
template <typename T>
auto adl_is_member_of_cppu(T && ) -> void;
}
Now we can write all three overloads:
namespace cppu
{
namespace detail
{
template <
typename T,
typename = std::enable_if_t<helper::is_member_of_cppu<T>::value and
not has_member_swap<T>::value>>
auto swap(T& x, T& y)
-> std::enable_if_t<helper::is_member_of_cppu<T>::value and
not has_member_swap<T>::value>
{
std::cout << "cppu-type without member swap";
std::swap(x, y);
}
template <
typename T,
typename = std::enable_if_t<not helper::is_member_of_cppu<T>::value and
not has_member_swap<T>::value>>
auto swap(T& x, T& y)
-> std::enable_if_t<not helper::is_member_of_cppu<T>::value and
not has_member_swap<T>::value>
{
std::cout << "not cppu-type without member swap";
using std::swap;
swap(x, y);
}
template <typename T, typename = std::enable_if_t<has_member_swap<T>::value>>
auto swap(T& x, T& y) -> decltype(x.swap(y))
{
std::cout << "member swap";
return x.swap(y);
}
}
}
Call this as you did before:
namespace cppu
{
template <typename T>
void swap(T& x, T& y)
{
detail::swap(x, y);
}
}
And finally: Test the whole thing.
namespace cppu
{
struct X{};
struct Y{ void swap(Y& y) { }; };
}
struct A{};
struct B{ void swap(B& y) { }; };
struct C{};
auto swap(C&, C&) -> void { std::cout << " with own overload"; }
static_assert(helper::is_member_of_cppu<cppu::X>::value, "");
static_assert(helper::is_member_of_cppu<cppu::Y>::value, "");
static_assert(not helper::is_member_of_cppu<A>::value, "");
static_assert(not helper::is_member_of_cppu<B>::value, "");
int main()
{
auto x1 = cppu::X{};
auto x2 = cppu::X{};
std::cout << "X: "; swap(x1, x2); std::cout << std::endl;
auto y1 = cppu::Y{};
auto y2 = cppu::Y{};
std::cout << "Y: "; swap(y1, y2); std::cout << std::endl;
auto a1 = A{};
auto a2 = A{};
std::cout << "A: "; cppu::swap(a1, a2); std::cout << std::endl;
auto b1 = B{};
auto b2 = B{};
std::cout << "B: "; cppu::swap(b1, b2); std::cout << std::endl;
auto c1 = C{};
auto c2 = C{};
std::cout << "C: "; cppu::swap(c1, c2); std::cout << std::endl;
}
The output is as expected (IMHO):
X: cppu-type without member swap
Y: member swap
A: not cppu-type without member swap
B: member swap
C: not cppu-type without member swap with own overload
Related
I have a function template which takes many different types as it's input. Out of those types only one of them has a getInt() function. Hence I want the code to run the function only for that type. Please suggest a solution. Thanks
#include <type_traits>
#include <typeinfo>
class X {
public:
int getInt(){
return 9;
}
};
class Y{
};
template<typename T>
void f(T& v){
// error: 'class Y' has no member named 'getInt'
// also tried std::is_same<T, X>::value
if(typeid(T).name() == typeid(X).name()){
int i = v.getInt();// I want this to be called for X only
}
}
int main(){
Y y;
f(y);
}
If you want to be able to call a function f for all types that have function member getInt, not just X, you can declare 2 overloads for function f:
for types that have getInt member function, including class X
for all the other types, including class Y.
C++11 / C++17 solution
Having that in mind, you could do something like this:
#include <iostream>
#include <type_traits>
template <typename, typename = void>
struct has_getInt : std::false_type {};
template <typename T>
struct has_getInt<T, std::void_t<decltype(((T*)nullptr)->getInt())>> : std::is_convertible<decltype(((T*)nullptr)->getInt()), int>
{};
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T,
typename std::enable_if<!has_getInt<T>::value, T>::type* = nullptr>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <typename T,
typename std::enable_if<has_getInt<T>::value, T>::type* = nullptr>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
Check it out live.
Please note that std::void_t is introduced in C++17, but if you are limited to C++11, then it is really easy to implement void_t on your own:
template <typename...>
using void_t = void;
And here is C++11 version live.
What do we have in C++20?
C++20 brings lots of good things and one of them is concepts. Above thing that's valid for C++11/C++14/C++17 can be significantly reduced in C++20:
#include <iostream>
#include <concepts>
template<typename T>
concept HasGetInt = requires (T& v) { { v.getInt() } -> std::convertible_to<int>; };
class X {
public:
int getInt(){
return 9;
}
};
class Y {};
template <typename T>
void f(T& v) {
// only for Y
std::cout << "Y" << std::endl;
}
template <HasGetInt T>
void f(T& v){
// only for X
int i = v.getInt();
std::cout << "X" << std::endl;
}
int main() {
X x;
f(x);
Y y;
f(y);
}
Check it out live.
You might use if constexpr from C++17:
template<typename T>
void f(T& v){
if constexpr(std::is_same_v<T, X>) { // Or better create trait has_getInt
int i = v.getInt();// I want this to be called for X only
}
// ...
}
Before, you will have to use overloads and SFINAE or tag dispatching.
Keep it simple and overload. Has worked since at least C++98...
template<typename T>
void f(T& v)
{
// do whatever
}
void f(X& v)
{
int result = v.getInt();
}
This is enough if there only ever one type with getInt function. If there's more, it's not so simple anymore. There are several ways to do it, here's one:
struct PriorityA { };
struct PriorityB : PriorityA { };
template<typename T>
void f_impl(T& t, PriorityA)
{
// generic version
}
// use expression SFINAE (-> decltype part)
// to enable/disable this overload
template<typename T>
auto f_impl(T& t, PriorityB) -> decltype(t.getInt(), void())
{
t.getInt();
}
template<typename T>
void f(T& t)
{
f_impl(t, PriorityB{ } ); // this will select PriorityB overload if it exists in overload set
// otherwise PriorityB gets sliced to PriorityA and calls generic version
}
Live example with diagnostic output.
Expanding on #nes code (https://codereview.stackexchange.com/questions/67241/function-composition-using-stdbind), is there a way to edit the code, so that the input to make_composition_function could be a vector of functions instead of functions as separate arguments.
#include <iostream>
#include <functional>
#include <vector>
// traits to infer the return type of recursive binds
template<typename... Fn>
struct composite_function_traits;
// bind a single function with a placeholder
template<typename F1>
struct composite_function_traits<F1> { typedef decltype(std::bind(std::declval<F1>(), std::placeholders::_1)) type; };
template<typename F1>
typename composite_function_traits<F1>::type make_composite_function(F1&& f1)
{
return std::bind(std::forward<F1>(f1), std::placeholders::_1);
}
// recursively bind multiple functions
template<typename F1, typename... Fn>
struct composite_function_traits<F1, Fn...> { typedef decltype(std::bind(std::declval<F1>(), std::declval<typename composite_function_traits<Fn...>::type>())) type; };
template<typename F1, typename... Fn>
typename composite_function_traits<F1, Fn...>::type make_composite_function(F1&& f1, Fn&&... fn)
{
return std::bind(std::forward<F1>(f1), make_composite_function(std::forward<Fn>(fn)...));
}
int main() {
using namespace std;
auto f1 = [] (int x) { cout << "f1" << endl; return x; };
auto f2 = [] (int x) { cout << "f2" << endl; return x; };
auto f3 = [] (int x) { cout << "f3" << endl; return x; };
// this works -> int y = make_composite_function(f1, f2, f3)(1);
// what I would like to be able to do
std::vector<std::function<int(int)>> funvec;
funvec.push_back(f1);
funvec.push_back(f2);
funvec.push_back(f3);
int y = make_composite_function(funvec)(1);
// print result
cout << y << endl;
}
You might do something like:
template <typename T>
std::function<T(T)> make_composite_function(std::vector<std::function<T(T)>> v)
{
std::reverse(v.begin(), v.end());
return [=](T t) {
for (const auto& f : v) {
t = f(t);
}
return t;
};
}
Demo
You don't even have to use SFINAE for previous overloads by passing vector by value.
My real example is quite big, so I will use a simplified one. Suppose I have a data-type for a rectangle:
struct Rectangle {
int width;
int height;
int computeArea() {
return width * height;
}
}
And another type that consumes that type, for example:
struct TwoRectangles {
Rectangle a;
Rectangle b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Now, I don't want to put ownership constraints on users of TwoRectangles, so I would like to make it a template:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Usages:
TwoRectangles<Rectangle> x;
TwoRectangles<Rectangle*> y;
TwoRectangles<std::shared_ptr<Rectangle>> z;
// etc...
The problem is that if the caller wants to use pointers, the body of the function should be different:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
assert(a && b);
return a->computeArea() + b->computeArea();
}
};
What is the best way of unifying my templated function so that the maxiumum amount of code is reused for pointers, values and smart pointers?
One way of doing this, encapsulating everything within TwoRectangles, would be something like:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
return areaOf(a) + areaOf(b);
}
private:
template <class U>
auto areaOf(U& v) -> decltype(v->computeArea()) {
return v->computeArea();
}
template <class U>
auto areaOf(U& v) -> decltype(v.computeArea()) {
return v.computeArea();
}
};
It's unlikely you'll have a type for which both of those expressions are valid. But you can always add additional disambiguation with a second argument to areaOf().
Another way, would be to take advantage of the fact that there already is a way in the standard library of invoking a function on whatever: std::invoke(). You just need to know the underlying type:
template <class T, class = void>
struct element_type {
using type = T;
};
template <class T>
struct element_type<T, void_t<typename std::pointer_traits<T>::element_type>> {
using type = typename std::pointer_traits<T>::element_type;
};
template <class T>
using element_type_t = typename element_type<T>::type;
and
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
using U = element_type_t<T>;
return std::invoke(&U::computeArea, a) +
std::invoke(&U::computeArea, b);
}
};
I actually had a similar problem some time ago, eventually i opted not to do it for now (because it's a big change), but it spawned a solution that seems to be correct.
I thought about making a helper function to access underlying value if there is any indirection. In code it would look like this, also with an example similar to yours.
#include <iostream>
#include <string>
#include <memory>
namespace detail
{
//for some reason the call for int* is ambiguous in newer standard (C++14?) when the function takes no parameters. That's a dirty workaround but it works...
template <class T, class SFINAE = decltype(*std::declval<T>())>
constexpr bool is_indirection(bool)
{
return true;
}
template <class T>
constexpr bool is_indirection(...)
{
return false;
}
}
template <class T>
constexpr bool is_indirection()
{
return detail::is_indirection<T>(true);
}
template <class T, bool ind = is_indirection<T>()>
struct underlying_type
{
using type = T;
};
template <class T>
struct underlying_type<T, true>
{
using type = typename std::remove_reference<decltype(*(std::declval<T>()))>::type;
};
template <class T>
typename std::enable_if<is_indirection<T>(), typename std::add_lvalue_reference<typename underlying_type<T>::type>::type>::type underlying_value(T&& val)
{
return *std::forward<T>(val);
}
template <class T>
typename std::enable_if<!is_indirection<T>(), T&>::type underlying_value(T& val)
{
return val;
}
template <class T>
typename std::enable_if<!is_indirection<T>(), const T&>::type underlying_value(const T& val)
{
return val;
}
template <class T>
class Storage
{
public:
T val;
void print()
{
std::cout << underlying_value(val) << '\n';
}
};
template <class T>
class StringStorage
{
public:
T str;
void printSize()
{
std::cout << underlying_value(str).size() << '\n';
}
};
int main()
{
int* a = new int(213);
std::string str = "some string";
std::shared_ptr<std::string> strPtr = std::make_shared<std::string>(str);
Storage<int> sVal{ 1 };
Storage<int*> sPtr{ a };
Storage<std::string> sStrVal{ str };
Storage<std::shared_ptr<std::string>> sStrPtr{ strPtr };
StringStorage<std::string> ssStrVal{ str };
StringStorage<const std::shared_ptr<std::string>> ssStrPtr{ strPtr };
sVal.print();
sPtr.print();
sStrVal.print();
sStrPtr.print();
ssStrVal.printSize();
ssStrPtr.printSize();
std::cout << is_indirection<int*>() << '\n';
std::cout << is_indirection<int>() << '\n';
std::cout << is_indirection<std::shared_ptr<int>>() << '\n';
std::cout << is_indirection<std::string>() << '\n';
std::cout << is_indirection<std::unique_ptr<std::string>>() << '\n';
}
I'm looking for a way to implement a function class
template<class ValueType>
class Function { ... };
which can be constructed with a function pointer (or functor) that takes any number of arguments of type ValueType and returns ValueType. For example, given these functions:
double foo(double);
double bar(double, double);
int baz(double, int);
a Function<double> object could be constructed with either foo or bar but not baz.
Then, a member function call will, given some container of ValueType (or an iterator), call the underlying function with the right number of arguments at runtime.
Is such thing possible?
It is indeed possible, you just have to "recursively" unpack arguments from the container and pass them to the function on the deepest level:
#include <cstddef>
#include <utility>
#include <stdexcept>
#include <functional>
#include <type_traits>
#include <vector>
#include <iostream>
namespace detail {
template <std::size_t argument_count>
struct arguments_unpacker {
template <typename Type, typename Function, typename InputIterator, typename... UnpackedArguments>
static Type unpack(Function&& function, InputIterator arguments_begin, InputIterator arguments_end, UnpackedArguments&&... unpacked_arguments) {
if (arguments_begin == arguments_end) {
throw std::invalid_argument("Not enough arguments.");
}
return arguments_unpacker<argument_count - 1>::template unpack<Type>(std::forward<Function>(function), std::next(arguments_begin), arguments_end, std::forward<UnpackedArguments>(unpacked_arguments)..., *arguments_begin);
}
};
template <>
struct arguments_unpacker<0> {
template <typename Type, typename Function, typename InputIterator, typename... UnpackedArguments>
static Type unpack(Function&& function, InputIterator arguments_begin, InputIterator arguments_end, UnpackedArguments&&... unpacked_arguments) {
if (arguments_begin != arguments_end) {
throw std::invalid_argument("Too many arguments.");
}
return function(std::forward<UnpackedArguments>(unpacked_arguments)...);
}
};
template <typename MemberFunction>
struct member_function_arity;
template <typename Result, typename Class, typename... Arguments>
struct member_function_arity<Result(Class::*)(Arguments...)> {
static constexpr std::size_t value = sizeof...(Arguments);
};
template <typename Result, typename Class, typename... Arguments>
struct member_function_arity<Result(Class::*)(Arguments...) const> {
static constexpr std::size_t value = sizeof...(Arguments);
};
template <typename Function>
struct function_arity : member_function_arity<decltype(&Function::operator())> {};
template <typename Result, typename... Arguments>
struct function_arity<Result(*)(Arguments...)> {
static constexpr std::size_t value = sizeof...(Arguments);
};
template <typename Result, typename... Arguments>
struct function_arity<std::function<Result(Arguments...)>> {
static constexpr std::size_t value = sizeof...(Arguments);
};
}
template <typename Type, typename InputIterator, typename Function>
std::function<Type(InputIterator, InputIterator)> variate(Function function) {
using namespace detail;
return [function](InputIterator arguments_begin, InputIterator arguments_end) {
return arguments_unpacker<function_arity<Function>::value>::template unpack<Type>(function, arguments_begin, arguments_end);
};
}
namespace demo {
double a(double x0) {
std::cout << "a(" << x0 << ")\n";
return 0.0;
}
double b(double x0, double x1) {
std::cout << "b(" << x0 << ", " << x1 << ")\n";
return 0.0;
}
double c(double x0, double x1, double x2) {
std::cout << "b(" << x0 << ", " << x1 << ", " << x2 << ")\n";
return 0.0;
}
auto l = [](double x0) mutable {
std::cout << "l(" << x0 << ")\n";
return 0.0;
};
void run() {
using it = std::vector<double>::const_iterator;
auto va = variate<double, it>(&a);
auto vb = variate<double, it>(&b);
auto vc = variate<double, it>(&c);
auto vl = variate<double, it>(l);
std::vector<double> a1 = {1.0};
std::vector<double> a2 = {1.0, 2.0};
std::vector<double> a3 = {1.0, 2.0, 3.0};
va(begin(a1), end(a1));
vb(begin(a2), end(a2));
vc(begin(a3), end(a3));
vl(begin(a1), end(a1));
}
}
int main()
{
demo::run();
return 0;
}
Note that this requres explicitly supplying iterator type. I don't see how it would be possible to remedy that without writing some kind of type erasing any_iterator.
#include <functional>
#include <boost/any.hpp>
template<class ValueType>
struct Function {
template <typename ...Args>
Function(const std::function<ValueType(Args...)>& f)
: fn(f)
{}
template <typename ...Args>
ValueType operator () (Args... args) {
auto f = boost::any_cast<const std::function<ValueType(Args...)>&>(fn);
return f(args...);
}
boost::any fn;
};
int a(int) { return 1; }
int b(int, double) { return 2; }
int main(int argc, char** argv)
{
typedef std::vector<Function<int>> Functions;
Functions functions {
std::function<int(int)>(a),
std::function<int(int, double)>(b)
};
std::cout << functions[0](1) << functions[1](1, 2.0) << std::endl;
}
I'm trying to create a function which can be called with a lambda that takes either 0, 1 or 2 arguments. Since I need the code to work on both g++ 4.5 and vs2010(which doesn't support variadic templates or lambda conversions to function pointers) the only idea I've come up with is to choose which implementation to call based on arity. The below is my non working guess at how this should look. Is there any way to fix my code or is there a better way to do this in general?
#include <iostream>
#include <functional>
using namespace std;
template <class Func> struct arity;
template <class Func>
struct arity<Func()>{ static const int val = 0; };
template <class Func, class Arg1>
struct arity<Func(Arg1)>{ static const int val = 1; };
template <class Func, class Arg1, class Arg2>
struct arity<Func(Arg1,Arg2)>{ static const int val = 2; };
template<class F>
void bar(F f)
{
cout << arity<F>::val << endl;
}
int main()
{
bar([]{cout << "test" << endl;});
}
A lambda function is a class type with a single function call operator. You can thus detect the arity of that function call operator by taking its address and using overload resolution to select which function to call:
#include <iostream>
template<typename F,typename R>
void do_stuff(F& f,R (F::*mf)() const)
{
(f.*mf)();
}
template<typename F,typename R,typename A1>
void do_stuff(F& f,R (F::*mf)(A1) const)
{
(f.*mf)(99);
}
template<typename F,typename R,typename A1,typename A2>
void do_stuff(F& f,R (F::*mf)(A1,A2) const)
{
(f.*mf)(42,123);
}
template<typename F>
void do_stuff(F f)
{
do_stuff(f,&F::operator());
}
int main()
{
do_stuff([]{std::cout<<"no args"<<std::endl;});
do_stuff([](int a1){std::cout<<"1 args="<<a1<<std::endl;});
do_stuff([](int a1,int a2){std::cout<<"2 args="<<a1<<","<<a2<<std::endl;});
}
Be careful though: this won't work with function types, or class types that have more than one function call operator, or non-const function call operators.
I thought the following would work but it doesn't, I'm posting it for two reasons.
To save people the time if they had the same idea
If someone knows why this doesn't work, I'm not 100% sure I understand (although I have my suspicions)
Code follows:
#include <iostream>
#include <functional>
template <typename Ret>
unsigned arity(std::function<Ret()>) { return 0; }
template <typename Ret, typename A1>
unsigned arity(std::function<Ret(A1)>) { return 1; }
template <typename Ret, typename A1, typename A2>
unsigned arity(std::function<Ret(A1, A2)>) { return 2; }
// rinse and repeat
int main()
{
std::function<void(int)> f = [](int i) { }; // this binds fine
// Error: no matching function for call to 'arity(main()::<lambda(int)>)'
std::cout << arity([](int i) { });
}
Compile time means of obtaining the arity of a function or a function object, including that of a lambda:
int main (int argc, char ** argv) {
auto f0 = []() {};
auto f1 = [](int) {};
auto f2 = [](int, void *) {};
std::cout << Arity<decltype(f0)>::value << std::endl; // 0
std::cout << Arity<decltype(f1)>::value << std::endl; // 1
std::cout << Arity<decltype(f2)>::value << std::endl; // 2
std::cout << Arity<decltype(main)>::value << std::endl; // 2
}
template <typename Func>
class Arity {
private:
struct Any {
template <typename T>
operator T ();
};
template <typename T>
struct Id {
typedef T type;
};
template <size_t N>
struct Size {
enum { value = N };
};
template <typename F>
static Size<0> match (
F f,
decltype(f()) * = nullptr);
template <typename F>
static Size<1> match (
F f,
decltype(f(Any())) * = nullptr,
decltype(f(Any())) * = nullptr);
template <typename F>
static Size<2> match (
F f,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr);
public:
enum { value = Id<decltype(match(static_cast<Func>(Any())))>::type::value };
};
This way works:
template<typename F>
auto call(F f) -> decltype(f(1))
{
return f(1);
}
template<typename F>
auto call(F f, void * fake = 0) -> decltype(f(2,3))
{
return f(2,3);
}
template<typename F>
auto call(F f, void * fake = 0, void * fake2 = 0) -> decltype(f(4,5,6))
{
return f(4,5,6);
}
int main()
{
auto x1 = call([](int a){ return a*10; });
auto x2 = call([](int a, int b){ return a*b; });
auto x3 = call([](int a, int b, int c){ return a*b*c; });
// x1 == 1*10
// x2 == 2*3
// x3 == 4*5*6
}
It works for all callable types (lambdas, functors, etc)