Is it possible to apply a generic function over tuple elements? - c++

I have found a for_each loop for tuples which just iterates over the elements and passes them into a function.
namespace std {
template<int I, class Tuple, typename F> struct for_each_impl {
static void for_each(const Tuple& t, F f) {
for_each_impl<I - 1, Tuple, F>::for_each(t, f);
f(get<I>(t));
}
};
template<class Tuple, typename F> struct for_each_impl<0, Tuple, F> {
static void for_each(const Tuple& t, F f) {
f(get<0>(t));
}
};
template<class Tuple, typename F>
void for_each(const Tuple& t, F f) {
for_each_impl<tuple_size<Tuple>::value - 1, Tuple, F>::for_each(t, f);
}
}
.
auto t = std::make_tuple(Foo(),Bar(),Baz());
std::for_each(t,[](???){});
Would it be possible to have a generic function like this?
std::for_each(t,[](T &&t){t.foo();});
In the end I just want to have something that works with every tuple.
std::get<0>(t).foo();
std::get<1>(t).foo();
std::get<2>(t).foo();
...
Maybe this would be easier with macros?

In c++14 you can use a generic lambda expression:
for_each(t, [] (auto&& t) { std::forward<decltype(t)>(t).foo(); });
In c++11 you can declare your own functor:
struct Lambda
{
template <typename T>
void operator()(T&& t) const { std::forward<T>(t).foo(); }
};
for_each(t, Lambda{});
or if, instead, you would like to apply a different function depending on the tuple element's type currently being processed, then once again a custom functor is the way to go:
struct Lambda
{
void operator()(const Foo& foo) const { foo.foo(); }
void operator()(const Bar& bar) const { bar.bar(); }
void operator()(const Baz& baz) const { baz.baz(); }
};
for_each(t, Lambda{});
And as a side note: do not define functions inside the std namespace.

Related

How can I do the type deduction on parameterized template function

#include <iostream>
template <typename... Ts> void Print(Ts... args) {
(std::cout << ... << args) << std::endl;
}
template <typename T> void Add(T a, T b) { Print(a + b); }
template <typename T> void Sub(T a, T b) { Print(a - b); }
template <typename T> void Mul(T a, T b) { Print(a * b); }
template <typename F, typename... Fns> void CallFuncs(F a, F b, Fns... fns) {
(fns(a, b), ...);
};
void FunctionInvokeTest() { CallFuncs(1, 2, Add<int>, Mul<int>); }
int main() {
FunctionInvokeTest();
return 0;
}
I want to pass the template function as parameter shown as above. The code works. However I must put <int> after the function such as Add<int>.
If this is non-deductible context, then is there another way to allow me write like this, where the Add and Mul are still template functions?
CallFuncs(1,2, Add, Mul);
You can't do it directly, but you can turn functions into function objects:
struct Add {
template<typename T>
void operator()(T a, T b) {
Print(a + b); }
};
struct Mul {
template<typename T>
void operator()(T a, T b) {
Print(a * b); }
};
template<typename F, typename... Fns>
void CallFuncs(F a, F b, Fns... fns) {
(fns(a, b), ...);
};
void FunctionInvokeTest() {
CallFuncs(1, 2, Add{}, Mul{});
}
T will be deduced from the type of a and b. In this example it will be int. To get double, you need double parameters:
CallFuncs(1., 2., Add{}, Mul{});
or explicit type specification:
CallFuncs<double>(1, 2, Add{}, Mul{});
This is very similar to "diamond" functors in the standard library (since C++14). For example, the std::plus declaration is
template<class T = void>
struct plus;
If T is void (e.g., in std::plus<>{}), plus::operator() deduces argument and return types. Typical implementation looks like this (with some minor simplifications):
template<> struct plus<void> {
template<typename Tp, typename Up>
constexpr auto operator()(Tp&& t, Up&& u) const {
return std::forward<Tp>(t) + std::forward<Up>(u);
}
};
If you can transform your template function into functor class, you might do:
struct Add {
template <typename T>
void operator ()(T a, T b) const { Print(a + b); }
};
struct Sub
{
template <typename T> void operator() (T a, T b) const { Print(a - b); }
};
struct Mul
{
template <typename T> void operator() (T a, T b) const { Print(a * b); }
};
Then you can do
void FunctionInvokeTest() { CallFuncs(1, 2, Add{}, Mul{}); }
Or to have more similar syntax:
constexpr Add add{};
constexpr Mul mul{};
void FunctionInvokeTest() { CallFuncs(1, 2, add, mul); }
If you cannot change your function, wrapping them in lambda might help:
void FunctionInvokeTest() { CallFuncs(1, 2,
[](auto lhs, auto rhs) { Add(lhs, rhs); },
[](auto lhs, auto rhs) { Mul(lhs, rhs); }); }
Workaround by moving function arguments into template
template <typename F>
using BinaryOp = void(F, F); // function type
// fns is now a pack of function objects instead of types
template <typename F, BinaryOp<F>... fns>
void CallFuncs(F a, F b) {
(fns(a, b), ...);
};
void FunctionInvokeTest() {
// the functions are now passed as template arguments alongside the desired numeric type
CallFuncs<float, Add, Mul>(1, 2);
}
https://godbolt.org/z/DutpHk

Restrict functor parameter type and constness

I am trying to implement a resource protection class which would combine data along with a shared mutex (actually, QReadWriteLock, but it's similar). The class must provide the method to apply a user-defined function to the data when the lock is acquired. I would like this apply method to work differently depending on the function parameter (reference, const reference, or value). For example, when the user passes a function like int (const DataType &) it shouldn't block exclusively as we are just reading the data and, conversely, when the function has the signature like void (DataType &) that implies data modification, hence the exclusive lock is needed.
My first attempt was to use std::function:
template <typename T>
class Resource1
{
public:
template <typename Result>
Result apply(std::function<Result(T &)> &&f)
{
QWriteLocker locker(&this->lock); // acquire exclusive lock
return std::forward<std::function<Result(T &)>>(f)(this->data);
}
template <typename Result>
Result apply(std::function<Result(const T &)> &&f) const
{
QReadLocker locker(&this->lock); // acquire shared lock
return std::forward<std::function<Result (const T &)>>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
But std::function doesn't seem to restrict parameter constness, so std::function<void (int &)> can easily accept void (const int &), which is not what I want. Also in this case it can't deduce lambda's result type, so I have to specify it manually:
Resource1<QList<int>> resource1;
resource1.apply<void>([](QList<int> &lst) { lst.append(11); }); // calls non-const version (ok)
resource1.apply<int>([](const QList<int> &lst) -> int { return lst.size(); }); // also calls non-const version (wrong)
My second attempt was to use std::result_of and return type SFINAE:
template <typename T>
class Resource2
{
public:
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f)
{
QWriteLocker locker(&this->lock); // lock exclusively
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const
{
QReadLocker locker(&this->lock); // lock non-exclusively
return std::forward<F>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
Resource2<QList<int>> resource2;
resource2.apply([](QList<int> &lst) {lst.append(12); }); // calls non-const version (ok)
resource2.apply([](const QList<int> &lst) { return lst.size(); }); // also calls non-const version (wrong)
Mainly the same thing happens: as long as the object is non-const the mutable version of apply gets called and result_of doesn't restrict anything.
Is there any way to achieve this?
You may do the following
template <std::size_t N>
struct overload_priority : overload_priority<N - 1> {};
template <> struct overload_priority<0> {};
using low_priority = overload_priority<0>;
using high_priority = overload_priority<1>;
template <typename T>
class Resource
{
public:
template <typename F>
auto apply(F&& f) const
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
template <typename F>
auto apply(F&& f)
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
private:
template <typename F>
auto apply_impl(F&& f, low_priority) -> decltype(f(std::declval<T&>()))
{
std::cout << "ReadLock\n";
return std::forward<F>(f)(this->data);
}
template <typename F>
auto apply_impl(F&& f, high_priority) -> decltype(f(std::declval<const T&>())) const
{
std::cout << "WriteLock\n";
return std::forward<F>(f)(this->data);
}
private:
T data;
};
Demo
Jarod has given a workaround, but I'll explain why you cannot achieve that this regular way.
The problem is that:
Overload resolution prefers non-const member functions over const member functions when called from a non-const object
whatever object this signature void foo(A&) can accept, void foo(const A&) can also the same object. The latter even has a broader binding set than the former.
Hence, to solve it, you will have to at least defeat point 1 before getting to 2. As Jarod has done.
From your signatures (see my comment annotations):
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f) //non-const member function
{
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const //const member function
{
return std::forward<F>(f)(this->data);
}
When you call it like:
resource2.apply([](QList<int> &lst) {lst.append(12); }); //1
resource2.apply([](const QList<int> &lst) { return lst.size(); }); //2
First of all, remember that resource2 isn't a const reference. Hence, the non-const membr function of apply will always be prefered by Overload resolution.
Now, taking the case of the first call //1, Whatever that lambda is callable with, then then the second one is also callable with that object
A simplified mock-up of what you are trying to do is:
struct A{
template<typename Func>
void foo(Func&& f); //enable if we can call f(B&);
template<typename Func>
void foo(Func&& f) const; //enable if we can call f(const B&);
};
void bar1(B&);
void bar2(const B&);
int main(){
A a;
a.foo(bar1);
a.foo(bar2);
//bar1 and bar2 can be both called with lvalues
B b;
bar1(b);
bar2(b);
}
As I understand it, you want to discriminate a parameter that's a std::function that takes a const reference versus a non-constant reference.
The following SFINAE-based approach seems to work, using a helper specialization class:
#include <functional>
#include <iostream>
template<typename ...Args>
using void_t=void;
template<typename Result,
typename T,
typename lambda,
typename void_t=void> class apply_helper;
template <typename T>
class Resource1
{
public:
template <typename Result, typename lambda>
Result apply(lambda &&l)
{
return apply_helper<Result, T, lambda>::helper(std::forward<lambda>(l));
}
};
template<typename Result, typename T, typename lambda, typename void_t>
class apply_helper {
public:
static Result helper(lambda &&l)
{
std::cout << "T &" << std::endl;
T t;
return l(t);
}
};
template<typename Result, typename T, typename lambda>
class apply_helper<Result, T, lambda,
void_t<decltype( std::declval<lambda>()( std::declval<T>()))>> {
public:
static Result helper(lambda &&l)
{
std::cout << "const T &" << std::endl;
return l( T());
}
};
Resource1<int> test;
int main()
{
auto lambda1=std::function<char (const int &)>([](const int &i)
{
return (char)i;
});
auto lambda2=std::function<char (int &)>([](int &i)
{
return (char)i;
});
auto lambda3=[](const int &i) { return (char)i; };
auto lambda4=[](int &i) { return (char)i; };
test.apply<char>(lambda1);
test.apply<char>(lambda2);
test.apply<char>(lambda3);
test.apply<char>(lambda4);
}
Output:
const T &
T &
const T &
T &
Demo
The helper() static class in the specialized class can now be modified to take a this parameter, instead, and then use it to trampoline back into the original template's class's method.
As long as the capture lists of your lambdas are empty, you can rely on the fact that such a lambda decays to a function pointer.
It's suffice to discriminate between the two types.
It follows a minimal, working example:
#include<iostream>
template <typename T>
class Resource {
public:
template <typename Result>
Result apply(Result(*f)(T &)) {
std::cout << "non-const" << std::endl;
return f(this->data);
}
template <typename Result>
Result apply(Result(*f)(const T &)) const {
std::cout << "const" << std::endl;
return f(this->data);
}
private:
T data;
};
int main() {
Resource<int> resource;
resource.apply<void>([](int &lst) { });
resource.apply<int>([](const int &lst) -> int { return 42; });
}

Implementing a compile-time "static-if" logic for different string types in a container

I'd like to write a function template that operates on a container of strings, for example a std::vector.
I'd like to support both CString and std::wstring with the same template function.
The problem is that CString and wstring have different interfaces, for example to get the "length" of a CString, you call the GetLength() method, instead for wstring you call size() or length().
If we had a "static if" feature in C++, I could write something like:
template <typename ContainerOfStrings>
void DoSomething(const ContainerOfStrings& strings)
{
for (const auto & s : strings)
{
static_if(strings::value_type is CString)
{
// Use the CString interface
}
static_else_if(strings::value_type is wstring)
{
// Use the wstring interface
}
}
}
Is there some template programming technique to achieve this goal with currently available C++11/14 tools?
PS
I know it's possible to write a couple of DoSomething() overloads with vector<CString> and vector<wstring>, but that's not the point of the question.
Moreover, I'd like this function template to work for any container on which you can iterate using a range-for loop.
#include <type_traits>
template <typename T, typename F>
auto static_if(std::true_type, T t, F f) { return t; }
template <typename T, typename F>
auto static_if(std::false_type, T t, F f) { return f; }
template <bool B, typename T, typename F>
auto static_if(T t, F f) { return static_if(std::integral_constant<bool, B>{}, t, f); }
template <bool B, typename T>
auto static_if(T t) { return static_if(std::integral_constant<bool, B>{}, t, [](auto&&...){}); }
Test:
template <typename ContainerOfStrings>
void DoSomething(const ContainerOfStrings& strings)
{
for (const auto & s : strings)
{
static_if<std::is_same<typename ContainerOfStrings::value_type, CString>{}>
([&](auto& ss)
{
// Use the CString interface
ss.GetLength();
})(s);
static_if<std::is_same<typename ContainerOfStrings::value_type, wstring>{}>
([&](auto& ss)
{
// Use the wstring interface
ss.size();
})(s);
}
}
DEMO
You could provide function overloads that do what you need:
size_t getSize(const std::string& str)
{
return str.size();
}
size_t getSize(const CString& str)
{
return str.GetLength();
}
template <typename ContainerOfStrings>
void DoSomething(const ContainerOfStrings& strings)
{
for (const auto & s : strings)
{
...
auto size = getSize(s);
...
}
}
Here is one with a pretty syntax.
The goal is to get rid of the extra ()s in #Piotr's solution.
Lots of boilerplate:
template<bool b>
struct static_if_t {};
template<bool b>
struct static_else_if_t {};
struct static_unsolved_t {};
template<class Op>
struct static_solved_t {
Op value;
template<class...Ts>
constexpr
decltype(auto) operator()(Ts&&...ts) {
return value(std::forward<Ts>(ts)...);
}
template<class Rhs>
constexpr
static_solved_t operator->*(Rhs&&)&&{
return std::move(*this);
}
};
template<class F>
constexpr
static_solved_t<std::decay_t<F>> static_solved(F&& f) {
return {std::forward<F>(f)};
}
template<class F>
constexpr
auto operator->*(static_if_t<true>, F&& f) {
return static_solved(std::forward<F>(f));
}
template<class F>
constexpr
static_unsolved_t operator->*(static_if_t<false>, F&&) {
return {};
}
constexpr
static_if_t<true> operator->*(static_unsolved_t, static_else_if_t<true>) {
return {};
}
constexpr
static_unsolved_t operator->*(static_unsolved_t, static_else_if_t<false>) {
return {};
}
template<bool b>
constexpr static_if_t<b> static_if{};
template<bool b>
constexpr static_else_if_t<b> static_else_if{};
constexpr static_else_if_t<true> static_else{};
Here is what it looks like at point of use:
template <typename ContainerOfStrings>
void DoSomething(const ContainerOfStrings& strings) {
for (const auto & s : strings)
{
auto op =
static_if<std::is_same<typename ContainerOfStrings::value_type,CString>{}>->*
[&](auto&& s){
// Use the CString interface
}
->*static_else_if<std::is_same<typename ContainerOfStrings::value_type, std::cstring>{}>->*
[&](auto&& s){
// Use the wstring interface
};
op(s); // fails to compile if both of the above tests fail
}
}
with an unlimited chain of static_else_ifs supported.
It does not prevent you from doing an unlimited chain of static_else (static_else in the above is just an alias for static_else_if<true>).
One common way to solve this is to extract the required interface out into a trait class. Something like this:
template <class S>
struct StringTraits
{
static size_t size(const S &s) { return s.size(); }
// More functions here
};
template <typename ContainerOfStrings>
void DoSomething(const ContainerOfStrings& strings)
{
for (const auto & s : strings)
{
auto len = StringTraits<typename std::decay<decltype(s)>::type>::size(s);
}
}
// Anyone can add their own specialisation of the traits, such as:
template <>
struct StringTraits<CString>
{
static size_t size(const CString &s) { return s.GetLength(); }
// More functions here
};
Of course, you can then go fancy and change the function itself to allow trait selection in addition to the type-based selection:
template <class ContainerOfStrings, class Traits = StringTraits<typename ContainerOfString::value_type>>
void DoSomething(const ContainerOfStrings& strings)
You could provide two overloads for getting the length:
template<typename T>
std::size_t getLength(T const &str)
{
return str.size();
}
std::size_t getLength(CString const &str)
{
return str.GetLength();
}

How do i use an iterator to access data within a tuple [duplicate]

How can I iterate over a tuple (using C++11)? I tried the following:
for(int i=0; i<std::tuple_size<T...>::value; ++i)
std::get<i>(my_tuple).do_sth();
but this doesn't work:
Error 1: sorry, unimplemented: cannot expand ‘Listener ...’ into a fixed-length argument list.
Error 2: i cannot appear in a constant expression.
So, how do I correctly iterate over the elements of a tuple?
I have an answer based on Iterating over a Tuple:
#include <tuple>
#include <utility>
#include <iostream>
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
print(std::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
print(std::tuple<Tp...>& t)
{
std::cout << std::get<I>(t) << std::endl;
print<I + 1, Tp...>(t);
}
int
main()
{
typedef std::tuple<int, float, double> T;
T t = std::make_tuple(2, 3.14159F, 2345.678);
print(t);
}
The usual idea is to use compile time recursion. In fact, this idea is used to make a printf that is type safe as noted in the original tuple papers.
This can be easily generalized into a for_each for tuples:
#include <tuple>
#include <utility>
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
Though this then requires some effort to have FuncT represent something with the appropriate overloads for every type the tuple might contain. This works best if you know all the tuple elements will share a common base class or something similar.
In C++17, you can use std::apply with fold expression:
std::apply([](auto&&... args) {((/* args.dosomething() */), ...);}, the_tuple);
A complete example for printing a tuple:
#include <tuple>
#include <iostream>
int main()
{
std::tuple t{42, 'a', 4.2}; // Another C++17 feature: class template argument deduction
std::apply([](auto&&... args) {((std::cout << args << '\n'), ...);}, t);
}
[Online Example on Coliru]
This solution solves the issue of evaluation order in M. Alaggan's answer.
C++ is introducing expansion statements for this purpose. They were originally on track for C++20 but narrowly missed the cut due to a lack of time for language wording review (see here and here).
The currently agreed syntax (see the links above) is:
{
auto tup = std::make_tuple(0, 'a', 3.14);
template for (auto elem : tup)
std::cout << elem << std::endl;
}
Boost.Fusion is a possibility:
Untested example:
struct DoSomething
{
template<typename T>
void operator()(T& t) const
{
t.do_sth();
}
};
tuple<....> t = ...;
boost::fusion::for_each(t, DoSomething());
In C++17 you can do this:
std::apply([](auto ...x){std::make_tuple(x.do_something()...);} , the_tuple);
This already works in Clang++ 3.9, using std::experimental::apply.
A more simple, intuitive and compiler-friendly way of doing this in C++17, using if constexpr:
// prints every element of a tuple
template<size_t I = 0, typename... Tp>
void print(std::tuple<Tp...>& t) {
std::cout << std::get<I>(t) << " ";
// do things
if constexpr(I+1 != sizeof...(Tp))
print<I+1>(t);
}
This is compile-time recursion, similar to the one presented by #emsr. But this doesn't use SFINAE so (I think) it is more compiler-friendly.
Use Boost.Hana and generic lambdas:
#include <tuple>
#include <iostream>
#include <boost/hana.hpp>
#include <boost/hana/ext/std/tuple.hpp>
struct Foo1 {
int foo() const { return 42; }
};
struct Foo2 {
int bar = 0;
int foo() { bar = 24; return bar; }
};
int main() {
using namespace std;
using boost::hana::for_each;
Foo1 foo1;
Foo2 foo2;
for_each(tie(foo1, foo2), [](auto &foo) {
cout << foo.foo() << endl;
});
cout << "foo2.bar after mutation: " << foo2.bar << endl;
}
http://coliru.stacked-crooked.com/a/27b3691f55caf271
Here's an easy C++17 way of iterating over tuple items with just standard library:
#include <tuple> // std::tuple
#include <functional> // std::invoke
template <
size_t Index = 0, // start iteration at 0 index
typename TTuple, // the tuple type
size_t Size =
std::tuple_size_v<
std::remove_reference_t<TTuple>>, // tuple size
typename TCallable, // the callable to be invoked for each tuple item
typename... TArgs // other arguments to be passed to the callable
>
void for_each(TTuple&& tuple, TCallable&& callable, TArgs&&... args)
{
if constexpr (Index < Size)
{
std::invoke(callable, args..., std::get<Index>(tuple));
if constexpr (Index + 1 < Size)
for_each<Index + 1>(
std::forward<TTuple>(tuple),
std::forward<TCallable>(callable),
std::forward<TArgs>(args)...);
}
}
Example:
#include <iostream>
int main()
{
std::tuple<int, char> items{1, 'a'};
for_each(items, [](const auto& item) {
std::cout << item << "\n";
});
}
Output:
1
a
This can be extended to conditionally break the loop in case the callable returns a value (but still work with callables that do not return a bool assignable value, e.g. void):
#include <tuple> // std::tuple
#include <functional> // std::invoke
template <
size_t Index = 0, // start iteration at 0 index
typename TTuple, // the tuple type
size_t Size =
std::tuple_size_v<
std::remove_reference_t<TTuple>>, // tuple size
typename TCallable, // the callable to bo invoked for each tuple item
typename... TArgs // other arguments to be passed to the callable
>
void for_each(TTuple&& tuple, TCallable&& callable, TArgs&&... args)
{
if constexpr (Index < Size)
{
if constexpr (std::is_assignable_v<bool&, std::invoke_result_t<TCallable&&, TArgs&&..., decltype(std::get<Index>(tuple))>>)
{
if (!std::invoke(callable, args..., std::get<Index>(tuple)))
return;
}
else
{
std::invoke(callable, args..., std::get<Index>(tuple));
}
if constexpr (Index + 1 < Size)
for_each<Index + 1>(
std::forward<TTuple>(tuple),
std::forward<TCallable>(callable),
std::forward<TArgs>(args)...);
}
}
Example:
#include <iostream>
int main()
{
std::tuple<int, char> items{ 1, 'a' };
for_each(items, [](const auto& item) {
std::cout << item << "\n";
});
std::cout << "---\n";
for_each(items, [](const auto& item) {
std::cout << item << "\n";
return false;
});
}
Output:
1
a
---
1
You need to use template metaprogramming, here shown with Boost.Tuple:
#include <boost/tuple/tuple.hpp>
#include <iostream>
template <typename T_Tuple, size_t size>
struct print_tuple_helper {
static std::ostream & print( std::ostream & s, const T_Tuple & t ) {
return print_tuple_helper<T_Tuple,size-1>::print( s, t ) << boost::get<size-1>( t );
}
};
template <typename T_Tuple>
struct print_tuple_helper<T_Tuple,0> {
static std::ostream & print( std::ostream & s, const T_Tuple & ) {
return s;
}
};
template <typename T_Tuple>
std::ostream & print_tuple( std::ostream & s, const T_Tuple & t ) {
return print_tuple_helper<T_Tuple,boost::tuples::length<T_Tuple>::value>::print( s, t );
}
int main() {
const boost::tuple<int,char,float,char,double> t( 0, ' ', 2.5f, '\n', 3.1416 );
print_tuple( std::cout, t );
return 0;
}
In C++0x, you can write print_tuple() as a variadic template function instead.
First define some index helpers:
template <size_t ...I>
struct index_sequence {};
template <size_t N, size_t ...I>
struct make_index_sequence : public make_index_sequence<N - 1, N - 1, I...> {};
template <size_t ...I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
With your function you would like to apply on each tuple element:
template <typename T>
/* ... */ foo(T t) { /* ... */ }
you can write:
template<typename ...T, size_t ...I>
/* ... */ do_foo_helper(std::tuple<T...> &ts, index_sequence<I...>) {
std::tie(foo(std::get<I>(ts)) ...);
}
template <typename ...T>
/* ... */ do_foo(std::tuple<T...> &ts) {
return do_foo_helper(ts, make_index_sequence<sizeof...(T)>());
}
Or if foo returns void, use
std::tie((foo(std::get<I>(ts)), 1) ... );
Note: On C++14 make_index_sequence is already defined (http://en.cppreference.com/w/cpp/utility/integer_sequence).
If you do need a left-to-right evaluation order, consider something like this:
template <typename T, typename ...R>
void do_foo_iter(T t, R ...r) {
foo(t);
do_foo(r...);
}
void do_foo_iter() {}
template<typename ...T, size_t ...I>
void do_foo_helper(std::tuple<T...> &ts, index_sequence<I...>) {
do_foo_iter(std::get<I>(ts) ...);
}
template <typename ...T>
void do_foo(std::tuple<T...> &ts) {
do_foo_helper(ts, make_index_sequence<sizeof...(T)>());
}
If you want to use std::tuple and you have C++ compiler which supports variadic templates, try code bellow (tested with g++4.5). This should be the answer to your question.
#include <tuple>
// ------------- UTILITY---------------
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};
// ----------- FOR EACH -----------------
template<typename Func, typename Last>
void for_each_impl(Func&& f, Last&& last)
{
f(last);
}
template<typename Func, typename First, typename ... Rest>
void for_each_impl(Func&& f, First&& first, Rest&&...rest)
{
f(first);
for_each_impl( std::forward<Func>(f), rest...);
}
template<typename Func, int ... Indexes, typename ... Args>
void for_each_helper( Func&& f, index_tuple<Indexes...>, std::tuple<Args...>&& tup)
{
for_each_impl( std::forward<Func>(f), std::forward<Args>(std::get<Indexes>(tup))...);
}
template<typename Func, typename ... Args>
void for_each( std::tuple<Args...>& tup, Func&& f)
{
for_each_helper(std::forward<Func>(f),
typename make_indexes<Args...>::type(),
std::forward<std::tuple<Args...>>(tup) );
}
template<typename Func, typename ... Args>
void for_each( std::tuple<Args...>&& tup, Func&& f)
{
for_each_helper(std::forward<Func>(f),
typename make_indexes<Args...>::type(),
std::forward<std::tuple<Args...>>(tup) );
}
boost::fusion is another option, but it requires its own tuple type: boost::fusion::tuple. Lets better stick to the standard! Here is a test:
#include <iostream>
// ---------- FUNCTOR ----------
struct Functor
{
template<typename T>
void operator()(T& t) const { std::cout << t << std::endl; }
};
int main()
{
for_each( std::make_tuple(2, 0.6, 'c'), Functor() );
return 0;
}
the power of variadic templates!
In MSVC STL there's a _For_each_tuple_element function (not documented):
#include <tuple>
// ...
std::tuple<int, char, float> values{};
std::_For_each_tuple_element(values, [](auto&& value)
{
// process 'value'
});
Another option would be to implement iterators for tuples. This has the advantage that you can use a variety of algorithms provided by the standard library and range-based for loops. An elegant approach to this is explained here https://foonathan.net/2017/03/tuple-iterator/. The basic idea is to turn tuples into a range with begin() and end() methods to provide iterators. The iterator itself returns a std::variant<...> which can then be visited using std::visit.
Here some examples:
auto t = std::tuple{ 1, 2.f, 3.0 };
auto r = to_range(t);
for(auto v : r)
{
std::visit(unwrap([](auto& x)
{
x = 1;
}), v);
}
std::for_each(begin(r), end(r), [](auto v)
{
std::visit(unwrap([](auto& x)
{
x = 0;
}), v);
});
std::accumulate(begin(r), end(r), 0.0, [](auto acc, auto v)
{
return acc + std::visit(unwrap([](auto& x)
{
return static_cast<double>(x);
}), v);
});
std::for_each(begin(r), end(r), [](auto v)
{
std::visit(unwrap([](const auto& x)
{
std::cout << x << std::endl;
}), v);
});
std::for_each(begin(r), end(r), [](auto v)
{
std::visit(overload(
[](int x) { std::cout << "int" << std::endl; },
[](float x) { std::cout << "float" << std::endl; },
[](double x) { std::cout << "double" << std::endl; }), v);
});
My implementation (which is heavily based on the explanations in the link above):
#ifndef TUPLE_RANGE_H
#define TUPLE_RANGE_H
#include <utility>
#include <functional>
#include <variant>
#include <type_traits>
template<typename Accessor>
class tuple_iterator
{
public:
tuple_iterator(Accessor acc, const int idx)
: acc_(acc), index_(idx)
{
}
tuple_iterator operator++()
{
++index_;
return *this;
}
template<typename T>
bool operator ==(tuple_iterator<T> other)
{
return index_ == other.index();
}
template<typename T>
bool operator !=(tuple_iterator<T> other)
{
return index_ != other.index();
}
auto operator*() { return std::invoke(acc_, index_); }
[[nodiscard]] int index() const { return index_; }
private:
const Accessor acc_;
int index_;
};
template<bool IsConst, typename...Ts>
struct tuple_access
{
using tuple_type = std::tuple<Ts...>;
using tuple_ref = std::conditional_t<IsConst, const tuple_type&, tuple_type&>;
template<typename T>
using element_ref = std::conditional_t<IsConst,
std::reference_wrapper<const T>,
std::reference_wrapper<T>>;
using variant_type = std::variant<element_ref<Ts>...>;
using function_type = variant_type(*)(tuple_ref);
using table_type = std::array<function_type, sizeof...(Ts)>;
private:
template<size_t Index>
static constexpr function_type create_accessor()
{
return { [](tuple_ref t) -> variant_type
{
if constexpr (IsConst)
return std::cref(std::get<Index>(t));
else
return std::ref(std::get<Index>(t));
} };
}
template<size_t...Is>
static constexpr table_type create_table(std::index_sequence<Is...>)
{
return { create_accessor<Is>()... };
}
public:
static constexpr auto table = create_table(std::make_index_sequence<sizeof...(Ts)>{});
};
template<bool IsConst, typename...Ts>
class tuple_range
{
public:
using tuple_access_type = tuple_access<IsConst, Ts...>;
using tuple_ref = typename tuple_access_type::tuple_ref;
static constexpr auto tuple_size = sizeof...(Ts);
explicit tuple_range(tuple_ref tuple)
: tuple_(tuple)
{
}
[[nodiscard]] auto begin() const
{
return tuple_iterator{ create_accessor(), 0 };
}
[[nodiscard]] auto end() const
{
return tuple_iterator{ create_accessor(), tuple_size };
}
private:
tuple_ref tuple_;
auto create_accessor() const
{
return [this](int idx)
{
return std::invoke(tuple_access_type::table[idx], tuple_);
};
}
};
template<bool IsConst, typename...Ts>
auto begin(const tuple_range<IsConst, Ts...>& r)
{
return r.begin();
}
template<bool IsConst, typename...Ts>
auto end(const tuple_range<IsConst, Ts...>& r)
{
return r.end();
}
template <class ... Fs>
struct overload : Fs... {
explicit overload(Fs&&... fs) : Fs{ fs }... {}
using Fs::operator()...;
template<class T>
auto operator()(std::reference_wrapper<T> ref)
{
return (*this)(ref.get());
}
template<class T>
auto operator()(std::reference_wrapper<const T> ref)
{
return (*this)(ref.get());
}
};
template <class F>
struct unwrap : overload<F>
{
explicit unwrap(F&& f) : overload<F>{ std::forward<F>(f) } {}
using overload<F>::operator();
};
template<typename...Ts>
auto to_range(std::tuple<Ts...>& t)
{
return tuple_range<false, Ts...>{t};
}
template<typename...Ts>
auto to_range(const std::tuple<Ts...>& t)
{
return tuple_range<true, Ts...>{t};
}
#endif
Read-only access is also supported by passing a const std::tuple<>& to to_range().
Others have mentioned some well-designed third-party libraries that you may turn to. However, if you are using C++ without those third-party libraries, the following code may help.
namespace detail {
template <class Tuple, std::size_t I, class = void>
struct for_each_in_tuple_helper {
template <class UnaryFunction>
static void apply(Tuple&& tp, UnaryFunction& f) {
f(std::get<I>(std::forward<Tuple>(tp)));
for_each_in_tuple_helper<Tuple, I + 1u>::apply(std::forward<Tuple>(tp), f);
}
};
template <class Tuple, std::size_t I>
struct for_each_in_tuple_helper<Tuple, I, typename std::enable_if<
I == std::tuple_size<typename std::decay<Tuple>::type>::value>::type> {
template <class UnaryFunction>
static void apply(Tuple&&, UnaryFunction&) {}
};
} // namespace detail
template <class Tuple, class UnaryFunction>
UnaryFunction for_each_in_tuple(Tuple&& tp, UnaryFunction f) {
detail::for_each_in_tuple_helper<Tuple, 0u>
::apply(std::forward<Tuple>(tp), f);
return std::move(f);
}
Note: The code compiles with any compiler supporing C++11, and it keeps consistency with design of the standard library:
The tuple need not be std::tuple, and instead may be anything that supports std::get and std::tuple_size; in particular, std::array and std::pair may be used;
The tuple may be a reference type or cv-qualified;
It has similar behavior as std::for_each, and returns the input UnaryFunction;
For C++14 (or laster version) users, typename std::enable_if<T>::type and typename std::decay<T>::type could be replaced with their simplified version, std::enable_if_t<T> and std::decay_t<T>;
For C++17 (or laster version) users, std::tuple_size<T>::value could be replaced with its simplified version, std::tuple_size_v<T>.
For C++20 (or laster version) users, the SFINAE feature could be implemented with the Concepts.
Using constexpr and if constexpr(C++17) this is fairly simple and straight forward:
template <std::size_t I = 0, typename ... Ts>
void print(std::tuple<Ts...> tup) {
if constexpr (I == sizeof...(Ts)) {
return;
} else {
std::cout << std::get<I>(tup) << ' ';
print<I+1>(tup);
}
}
I might have missed this train, but this will be here for future reference.
Here's my construct based on this answer and on this gist:
#include <tuple>
#include <utility>
template<std::size_t N>
struct tuple_functor
{
template<typename T, typename F>
static void run(std::size_t i, T&& t, F&& f)
{
const std::size_t I = (N - 1);
switch(i)
{
case I:
std::forward<F>(f)(std::get<I>(std::forward<T>(t)));
break;
default:
tuple_functor<I>::run(i, std::forward<T>(t), std::forward<F>(f));
}
}
};
template<>
struct tuple_functor<0>
{
template<typename T, typename F>
static void run(std::size_t, T, F){}
};
You then use it as follow:
template<typename... T>
void logger(std::string format, T... args) //behaves like C#'s String.Format()
{
auto tp = std::forward_as_tuple(args...);
auto fc = [](const auto& t){std::cout << t;};
/* ... */
std::size_t some_index = ...
tuple_functor<sizeof...(T)>::run(some_index, tp, fc);
/* ... */
}
There could be room for improvements.
As per OP's code, it would become this:
const std::size_t num = sizeof...(T);
auto my_tuple = std::forward_as_tuple(t...);
auto do_sth = [](const auto& elem){/* ... */};
for(int i = 0; i < num; ++i)
tuple_functor<num>::run(i, my_tuple, do_sth);
Of all the answers I've seen here, here and here, I liked #sigidagi's way of iterating best. Unfortunately, his answer is very verbose which in my opinion obscures the inherent clarity.
This is my version of his solution which is more concise and works with std::tuple, std::pair and std::array.
template<typename UnaryFunction>
void invoke_with_arg(UnaryFunction)
{}
/**
* Invoke the unary function with each of the arguments in turn.
*/
template<typename UnaryFunction, typename Arg0, typename... Args>
void invoke_with_arg(UnaryFunction f, Arg0&& a0, Args&&... as)
{
f(std::forward<Arg0>(a0));
invoke_with_arg(std::move(f), std::forward<Args>(as)...);
}
template<typename Tuple, typename UnaryFunction, std::size_t... Indices>
void for_each_helper(Tuple&& t, UnaryFunction f, std::index_sequence<Indices...>)
{
using std::get;
invoke_with_arg(std::move(f), get<Indices>(std::forward<Tuple>(t))...);
}
/**
* Invoke the unary function for each of the elements of the tuple.
*/
template<typename Tuple, typename UnaryFunction>
void for_each(Tuple&& t, UnaryFunction f)
{
using size = std::tuple_size<typename std::remove_reference<Tuple>::type>;
for_each_helper(
std::forward<Tuple>(t),
std::move(f),
std::make_index_sequence<size::value>()
);
}
Demo: coliru
C++14's std::make_index_sequence can be implemented for C++11.
Expanding on #Stypox answer, we can make their solution more generic (C++17 onward). By adding a callable function argument:
template<size_t I = 0, typename... Tp, typename F>
void for_each_apply(std::tuple<Tp...>& t, F &&f) {
f(std::get<I>(t));
if constexpr(I+1 != sizeof...(Tp)) {
for_each_apply<I+1>(t, std::forward<F>(f));
}
}
Then, we need a strategy to visit each type.
Let start with some helpers (first two taken from cppreference):
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template<class ... Ts> struct variant_ref { using type = std::variant<std::reference_wrapper<Ts>...>; };
variant_ref is used to allow tuples' state to be modified.
Usage:
std::tuple<Foo, Bar, Foo> tuples;
for_each_apply(tuples,
[](variant_ref<Foo, Bar>::type &&v) {
std::visit(overloaded {
[](Foo &arg) { arg.foo(); },
[](Bar const &arg) { arg.bar(); },
}, v);
});
Result:
Foo0
Bar
Foo0
Foo1
Bar
Foo1
For completeness, here are my Bar & Foo:
struct Foo {
void foo() {std::cout << "Foo" << i++ << std::endl;}
int i = 0;
};
struct Bar {
void bar() const {std::cout << "Bar" << std::endl;}
};
I have stumbled on the same problem for iterating over a tuple of function objects, so here is one more solution:
#include <tuple>
#include <iostream>
// Function objects
class A
{
public:
inline void operator()() const { std::cout << "A\n"; };
};
class B
{
public:
inline void operator()() const { std::cout << "B\n"; };
};
class C
{
public:
inline void operator()() const { std::cout << "C\n"; };
};
class D
{
public:
inline void operator()() const { std::cout << "D\n"; };
};
// Call iterator using recursion.
template<typename Fobjects, int N = 0>
struct call_functors
{
static void apply(Fobjects const& funcs)
{
std::get<N>(funcs)();
// Choose either the stopper or descend further,
// depending if N + 1 < size of the tuple.
using caller = std::conditional_t
<
N + 1 < std::tuple_size_v<Fobjects>,
call_functors<Fobjects, N + 1>,
call_functors<Fobjects, -1>
>;
caller::apply(funcs);
}
};
// Stopper.
template<typename Fobjects>
struct call_functors<Fobjects, -1>
{
static void apply(Fobjects const& funcs)
{
}
};
// Call dispatch function.
template<typename Fobjects>
void call(Fobjects const& funcs)
{
call_functors<Fobjects>::apply(funcs);
};
using namespace std;
int main()
{
using Tuple = tuple<A,B,C,D>;
Tuple functors = {A{}, B{}, C{}, D{}};
call(functors);
return 0;
}
Output:
A
B
C
D
There're many great answers, but for some reason most of them don't consider returning the results of applying f to our tuple...
or did I overlook it? Anyway, here's yet another way you can do that:
Doing Foreach with style (debatable)
auto t = std::make_tuple(1, "two", 3.f);
t | foreach([](auto v){ std::cout << v << " "; });
And returning from that:
auto t = std::make_tuple(1, "two", 3.f);
auto sizes = t | foreach([](auto v) {
return sizeof(v);
});
sizes | foreach([](auto v) {
std::cout << v;
});
Implementation (pretty simple one)
Edit: it gets a little messier.
I won't include some metaprogramming boilerplate here, for it will definitely make things less readable and besides, I believe those have already been answered somewhere on stackoverflow.
In case you're feeling lazy, feel free to peek into my github repo for implementation of both
#include <utility>
// Optional includes, if you don't want to implement it by hand or google it
// you can find it in the repo (link below)
#include "typesystem/typelist.hpp"
// used to check if all return types are void,
// making it a special case
// (and, alas, not using constexpr-if
// for the sake of being compatible with C++14...)
template <bool Cond, typename T, typename F>
using select = typename std::conditional<Cond, T, F>::type;
template <typename F>
struct elementwise_apply {
F f;
};
template <typename F>
constexpr auto foreach(F && f) -> elementwise_apply<F> { return {std::forward<F>(f)}; }
template <typename R>
struct tuple_map {
template <typename F, typename T, size_t... Is>
static constexpr decltype(auto) impl(std::index_sequence<Is...>, F && f, T&& tuple) {
return R{ std::forward<F>(f)( std::get<Is>(tuple) )... };
}
};
template<>
struct tuple_map<void> {
template <typename F, typename T, size_t... Is>
static constexpr void impl(std::index_sequence<Is...>, F && f, T&& tuple) {
[[maybe_unused]] std::initializer_list<int> _ {((void)std::forward<F>(f)( std::get<Is>(tuple) ), 0)... };
}
};
template <typename F, typename... Ts>
constexpr decltype(auto) operator| (std::tuple<Ts...> & t, fmap<F> && op) {
constexpr bool all_void = core::Types<decltype( std::move(op).f(std::declval<Ts&>()) )...>.all( core::is_void );
using R = meta::select<all_void, void, std::tuple<decltype(std::move(op).f(std::declval<Ts&>()))...>>;
return tuple_map<R>::impl(std::make_index_sequence<sizeof...(Ts)>{}, std::move(op).f, t);
}
template <typename F, typename... Ts>
constexpr decltype(auto) operator| (std::tuple<Ts...> const& t, fmap<F> && op) {
constexpr bool all_void = check if all "decltype( std::move(op).f(std::declval<Ts>()) )..." types are void, since then it's a special case
// e.g. core::Types<decltype( std::move(op).f(std::declval<Ts>()) )...>.all( core::is_void );
using R = meta::select<all_void, void, std::tuple<decltype(std::move(op).f(std::declval<Ts const&>()))...>>;
return tuple_map<R>::impl(std::make_index_sequence<sizeof...(Ts)>{}, std::move(op).f, t);
}
template <typename F, typename... Ts>
constexpr decltype(auto) operator| (std::tuple<Ts...> && t, fmap<F> && op) {
constexpr bool all_void = core::Types<decltype( std::move(op).f(std::declval<Ts&&>()) )...>.all( core::is_void );
using R = meta::select<all_void, void, std::tuple<decltype(std::move(op).f(std::declval<Ts&&>()))...>>;
return tuple_map<R>::impl(std::make_index_sequence<sizeof...(Ts)>{}, std::move(op).f, std::move(t));
}
Yeah, that would be much nicer if we were to use C++17
This is also an example of std::moving object's members, for which I'll better refer to this nice brief article
P.S. If you're stuck checking if all "decltype( std::move(op).f(std::declval()) )..." types are void
you can find some metaprogramming library, or, if those libraries seem too hard to grasp (which some of them may be due to some crazy metaprogramming tricks), you know where to look
template <typename F, typename T>
static constexpr size_t
foreach_in_tuple(std::tuple<T> & tuple, F && do_, size_t index_ = 0)
{
do_(tuple, index_);
return index_;
}
template <typename F, typename T, typename U, typename... Types>
static constexpr size_t
foreach_in_tuple(std::tuple<T,U,Types...> & tuple, F && do_, size_t index_ = 0)
{
if(!do_(tuple, index_))
return index_;
auto & next_tuple = reinterpret_cast<std::tuple<U,Types...> &>(tuple);
return foreach_in_tuple(next_tuple, std::forward<F>(do_), index_+1);
}
int main()
{
using namespace std;
auto tup = make_tuple(1, 2.3f, 'G', "hello");
foreach_in_tuple(tup, [](auto & tuple, size_t i)
{
auto & value = std::get<0>(tuple);
std::cout << i << " " << value << std::endl;
// if(i >= 2) return false; // break;
return true; // continue
});
}
Here is a solution based on std::interger_sequence.
As I don't know if my_tuple is constructed from std::make_tuple<T>(T &&...) in your code. It's essential for how to construct std::integer_sequence in the solution below.
(1) if your already have a my_tuple outside your function(not using template<typename ...T>), You can use
[](auto my_tuple)
{
[&my_tuple]<typename N, N... n>(std::integer_sequence<N, n...> int_seq)
{
((std::cout << std::get<n>(my_tuple) << '\n'), ...);
}(std::make_index_sequence<std::tuple_size_v<decltype(my_tuple)>>{});
}(std::make_tuple());
(2) if your havn't constructed my_tuple in your function and want to handle your T ...arguments
[]<typename ...T>(T... args)
{
[&args...]<typename N, N... n>(std::integer_sequence<N, n...> int_seq)
{
((std::cout << std::get<n>(std::forward_as_tuple(args...)) << '\n'), ...);
}(std::index_sequence_for<T...>{});
}();
boost's tuple provides helper functions get_head() and get_tail() so your helper functions may look like this:
inline void call_do_sth(const null_type&) {};
template <class H, class T>
inline void call_do_sth(cons<H, T>& x) { x.get_head().do_sth(); call_do_sth(x.get_tail()); }
as described in here http://www.boost.org/doc/libs/1_34_0/libs/tuple/doc/tuple_advanced_interface.html
with std::tuple it should be similar.
Actually, unfortunately std::tuple does not seem to provide such interface, so methods suggested before should work, or you would need to switch to boost::tuple which has other benefits (like io operators already provided). Though there is downside of boost::tuple with gcc - it does not accept variadic templates yet, but that may be already fixed as I do not have latest version of boost installed on my machine.

5 years later, is there something better than the "Fastest Possible C++ Delegates"?

I know that the topic of "C++ delegates" has been done to death, and both http://www.codeproject.com and http://stackoverflow.com deeply cover the question.
Generally, it seems that Don Clugston's fastest possible delegate is the first choice for many people. There are a few other popular ones.
However, I noticed that most of those articles are old (around 2005) and many design choices seem to have been made taking in account old compilers like VC7.
I'm in need of a very fast delegate implementation for an audio application.
I still need it to be portable (Windows, Mac, Linux) but I only use modern compilers (VC9, the one in VS2008 SP1 and GCC 4.5.x).
My main criteria are:
it must be fast!
it must be forward-compatible with newer versions of the compilers. I have some doubts about that with Don's implementation because he explicitly states it's not standard-compliant.
optionally, a KISS-syntax and ease-of-use is nice to have
multicast would be nice, although I'm convinced it's really easy to build it around any delegate library
Furthermore, I don't really need exotic features. I just need the good old pointer-to-method thing. No need to support static methods, free functions or things like that.
As of today, what is the recommended approach? Still use Don's version?
Or is there a "community consensus" about another option?
I really don't want to use Boost.signal/signal2 because it's not acceptable in terms of performance. A dependency on QT is not acceptable as well.
Furthermore, I've seen some newer libraries while googling, like for example cpp-events but I couldn't find any feedback from users, including on SO.
Update: An article with the complete source code and a more detailed discussion has been posted on The Code Project.
Well, the problem with pointers to methods is that they're not all the same size. So instead of storing pointers to methods directly, we need to "standardize" them so that they are of a constant size. This is what Don Clugston attempts to achieve in his Code Project article. He does so using intimate knowledge of the most popular compilers. I assert that it's possible to do it in "normal" C++ without requiring such knowledge.
Consider the following code:
void DoSomething(int)
{
}
void InvokeCallback(void (*callback)(int))
{
callback(42);
}
int main()
{
InvokeCallback(&DoSomething);
return 0;
}
This is one way to implement a callback using a plain old function pointer. However, this doesn't work for methods in objects. Let's fix this:
class Foo
{
public:
void DoSomething(int) {}
static void DoSomethingWrapper(void* obj, int param)
{
static_cast<Foo*>(obj)->DoSomething(param);
}
};
void InvokeCallback(void* instance, void (*callback)(void*, int))
{
callback(instance, 42);
}
int main()
{
Foo f;
InvokeCallback(static_cast<void*>(&f), &Foo::DoSomethingWrapper);
return 0;
}
Now, we have a system of callbacks that can work for both free and member functions. This, however, is clumsy and error-prone. However, there is a pattern - the use of a wrapper function to "forward" the static function call to a method call on the proper instance. We can use templates to help with this - let's try generalizing the wrapper function:
template<typename R, class T, typename A1, R (T::*Func)(A1)>
R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(void* instance, void (*callback)(void*, int))
{
callback(instance, 42);
}
int main()
{
Foo f;
InvokeCallback(static_cast<void*>(&f),
&Wrapper<void, Foo, int, &Foo::DoSomething> );
return 0;
}
This is still extremely clumsy, but at least now we don't have to write out a wrapper function every single time (at least for the 1 argument case). Another thing we can generalize is the fact that we're always passing a pointer to void*. Instead of passing it as two different values, why not put them together? And while we're doing that, why not generalize it as well? Hey, let's throw in an operator()() so we can call it like a function!
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1, R (T::*Func)(A1)>
R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
Callback<void, int> cb(static_cast<void*>(&f),
&Wrapper<void, Foo, int, &Foo::DoSomething>);
InvokeCallback(cb);
return 0;
}
We're making progress! But now our problem is the fact that the syntax is absolutely horrible. The syntax appears redundant; can't the compiler figure out the types from the pointer to method itself? Unfortunately no, but we can help it along. Remember that a compiler can deduce types via template argument deduction in a function call. So why don't we start with that?
template<typename R, class T, typename A1>
void DeduceMemCallback(R (T::*)(A1)) {}
Inside the function, we know what R, T and A1 is. So what if we can construct a struct that can "hold" these types and return them from the function?
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag2<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
And since DeduceMemCallbackTag knows about the types, why not put our wrapper function as a static function in it? And since the wrapper function is in it, why not put the code to construct our Callback object in it?
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R, A1> Bind(T* o)
{
return Callback<R, A1>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
The C++ standard allows us to call static functions on instances (!):
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
InvokeCallback(
DeduceMemCallback(&Foo::DoSomething)
.Bind<&Foo::DoSomething>(&f)
);
return 0;
}
Still, it's a lengthy expression, but we can put that into a simple macro (!):
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R, A1> Bind(T* o)
{
return Callback<R, A1>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
#define BIND_MEM_CB(memFuncPtr, instancePtr) \
(DeduceMemCallback(memFuncPtr).Bind<(memFuncPtr)>(instancePtr))
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
InvokeCallback(BIND_MEM_CB(&Foo::DoSomething, &f));
return 0;
}
We can enhance the Callback object by adding a safe bool. It's also a good idea to disable the equality operators since it's not possible to compare two Callback objects. Even better, is to use partial specialization to allow for a "preferred syntax". This gives us:
template<typename FuncSignature>
class Callback;
template<typename R, typename A1>
class Callback<R (A1)>
{
public:
typedef R (*FuncType)(void*, A1);
Callback() : obj(0), func(0) {}
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType() const
{
return func != 0? &Callback::obj : 0;
}
bool operator!() const
{
return func == 0;
}
private:
void* obj;
FuncType func;
};
template<typename R, typename A1> // Undefined on purpose
void operator==(const Callback<R (A1)>&, const Callback<R (A1)>&);
template<typename R, typename A1>
void operator!=(const Callback<R (A1)>&, const Callback<R (A1)>&);
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R (A1)> Bind(T* o)
{
return Callback<R (A1)>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
#define BIND_MEM_CB(memFuncPtr, instancePtr) \
(DeduceMemCallback(memFuncPtr).Bind<(memFuncPtr)>(instancePtr))
Usage example:
class Foo
{
public:
float DoSomething(int n) { return n / 100.0f; }
};
float InvokeCallback(int n, Callback<float (int)> callback)
{
if(callback) { return callback(n); }
return 0.0f;
}
int main()
{
Foo f;
float result = InvokeCallback(97, BIND_MEM_CB(&Foo::DoSomething, &f));
// result == 0.97
return 0;
}
I have tested this on the Visual C++ compiler (version 15.00.30729.01, the one that comes with VS 2008), and you do need a rather recent compiler to use the code. By inspection of the disassembly, the compiler was able to optimize away the wrapper function and the DeduceMemCallback call, reducing down to simple pointer assignments.
It's simple to use for both sides of the callback, and uses only (what I believe to be) standard C++. The code I've shown above works for member functions with 1 argument, but can be generalized to more arguments. It can also be further generalized by allowing support for static functions.
Note that the Callback object requires no heap allocation - they are of a constant size thanks to this "standardization" procedure. Because of this, it's possible to have a Callback object be a member of larger class, since it has a default constructor. It is also assignable (the compiler generated copy assignment functions are sufficient). It is also typesafe, thanks to the templates.
I wanted to follow off of #Insilico's answer with a bit of my own stuff.
Before I had stumbled upon this answer, I was trying to figure out fast callbacks as well that incurred no overhead and were uniquely comparable / identified by function signature only. What I ended up creating - with some serious help from Klingons Who Happened To Be at a BBQ - works for all function types (except Lambdas, unless you store the Lambda, but don't try it because it's really difficult and hard to do and may result in a robot proving to you how difficult it is and making you eat the shit for it). Thanks to #sehe, #nixeagle, #StackedCrooked, #CatPlusPlus, #Xeo, #DeadMG and of course #Insilico for the help in creating the event system. Feel free to use as you desire.
Anyway, an example is up on ideone, but the source code is also here for your use (because, since Liveworkspace went down, I don't trust them shady compiling services. Who knows when ideone will go down?!). I hope this is useful for somebody who's not busy Lambda/Function-objecting the world to pieces:
IMPORTANT NOTE: As of right now (28/11/2012, 9:35 PM) This variadic version will not work with the Microsoft VC++ 2012 November CTP (Milan). If you want to use it with that, you will have to get rid of all the variadic stuff and explicitly enumerate the number of arguments (and possibly template-specialize the 1-argument type for Event for void) to make it work. It's a pain, and I could only manage to write it out for 4 arguments before I got tired (and decided that passing more than 4 arguments was a bit of a stretch).
Source Example
Source:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
template<typename TFuncSignature>
class Callback;
template<typename R, typename... Args>
class Callback<R(Args...)> {
public:
typedef R(*TFunc)(void*, Args...);
Callback() : obj(0), func(0) {}
Callback(void* o, TFunc f) : obj(o), func(f) {}
R operator()(Args... a) const {
return (*func)(obj, std::forward<Args>(a)...);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType() const {
return func? &Callback::obj : 0;
}
bool operator!() const {
return func == 0;
}
bool operator== (const Callback<R (Args...)>& right) const {
return obj == right.obj && func == right.func;
}
bool operator!= (const Callback<R (Args...)>& right) const {
return obj != right.obj || func != right.func;
}
private:
void* obj;
TFunc func;
};
namespace detail {
template<typename R, class T, typename... Args>
struct DeduceConstMemCallback {
template<R(T::*Func)(Args...) const> inline static Callback<R(Args...)> Bind(T* o) {
struct _ { static R wrapper(void* o, Args... a) { return (static_cast<T*>(o)->*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(o, (R(*)(void*, Args...)) _::wrapper);
}
};
template<typename R, class T, typename... Args>
struct DeduceMemCallback {
template<R(T::*Func)(Args...)> inline static Callback<R(Args...)> Bind(T* o) {
struct _ { static R wrapper(void* o, Args... a) { return (static_cast<T*>(o)->*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(o, (R(*)(void*, Args...)) _::wrapper);
}
};
template<typename R, typename... Args>
struct DeduceStaticCallback {
template<R(*Func)(Args...)> inline static Callback<R(Args...)> Bind() {
struct _ { static R wrapper(void*, Args... a) { return (*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(0, (R(*)(void*, Args...)) _::wrapper);
}
};
}
template<typename R, class T, typename... Args>
detail::DeduceConstMemCallback<R, T, Args...> DeduceCallback(R(T::*)(Args...) const) {
return detail::DeduceConstMemCallback<R, T, Args...>();
}
template<typename R, class T, typename... Args>
detail::DeduceMemCallback<R, T, Args...> DeduceCallback(R(T::*)(Args...)) {
return detail::DeduceMemCallback<R, T, Args...>();
}
template<typename R, typename... Args>
detail::DeduceStaticCallback<R, Args...> DeduceCallback(R(*)(Args...)) {
return detail::DeduceStaticCallback<R, Args...>();
}
template <typename... T1> class Event {
public:
typedef void(*TSignature)(T1...);
typedef Callback<void(T1...)> TCallback;
typedef std::vector<TCallback> InvocationTable;
protected:
InvocationTable invocations;
public:
const static int ExpectedFunctorCount = 2;
Event() : invocations() {
invocations.reserve(ExpectedFunctorCount);
}
template <void (* TFunc)(T1...)> void Add() {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>();
invocations.push_back(c);
}
template <typename T, void (T::* TFunc)(T1...)> void Add(T& object) {
Add<T, TFunc>(&object);
}
template <typename T, void (T::* TFunc)(T1...)> void Add(T* object) {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>(object);
invocations.push_back(c);
}
template <typename T, void (T::* TFunc)(T1...) const> void Add(T& object) {
Add<T, TFunc>(&object);
}
template <typename T, void (T::* TFunc)(T1...) const> void Add(T* object) {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>(object);
invocations.push_back(c);
}
void Invoke(T1... t1) {
for(size_t i = 0; i < invocations.size() ; ++i) invocations[i](std::forward<T1>(t1)...);
}
void operator()(T1... t1) {
Invoke(std::forward<T1>(t1)...);
}
size_t InvocationCount() { return invocations.size(); }
template <void (* TFunc)(T1...)> bool Remove ()
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>()); }
template <typename T, void (T::* TFunc)(T1...)> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1...)> bool Remove (T* object)
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>(object)); }
template <typename T, void (T::* TFunc)(T1...) const> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1...) const> bool Remove (T* object)
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>(object)); }
protected:
bool Remove( TCallback const& target ) {
auto it = std::find(invocations.begin(), invocations.end(), target);
if (it == invocations.end())
return false;
invocations.erase(it);
return true;
}
};