How do I access variadic members? - c++

template<typename... Types>
struct Foo;
template<typename T , typename... Types>
struct Foo<T, Types ...> : public Foo<Types ...>
{
Foo( T member , Types ... others ) : Foo<Types ...>( others... ), m_member( member )
{
}
T m_member;
};
template<typename T>
struct Foo<T>
{
Foo( T member ) : m_member( member )
{
}
T m_member;
};
int main()
{
Foo<char,int,bool,double> f( 'a' , 42 , true , 1.234 );
}
I found this code somewhere on SO and I am wondering if it's completely useless? It seems to me that all members are called m_member so how would I access them?
If I do cout << f.m_member; it will print 'a', but I see no way to access the other members.

In your current implementation each derived Foo class shadows its parent's m_member. It is up to you how to implement a logic of accessing each field (via indexing, types, other).
One possibility is to access them by an overloaded templated member function taking a type or an index (reversed for simplicity):
#include <type_traits>
#include <cstddef>
template <typename... Types>
struct Foo;
template <typename T, typename... Types>
struct Foo<T, Types...> : Foo<Types...>
{
// bring get() member functions from parent class into current scope
using Foo<Types...>::get;
Foo(T member, Types... others) : Foo<Types...>{others...}, m_member{member} {}
template <typename U>
auto get(T* = nullptr)
-> typename std::enable_if<std::is_same<U, T>::value, T&>::type
{
return m_member;
}
template <std::size_t N>
auto get(T* = nullptr)
-> typename std::enable_if<N == sizeof...(Types), T&>::type
{
return m_member;
}
private:
T m_member;
};
template <typename T>
struct Foo<T>
{
Foo(T member) : m_member{member} {}
template <typename U>
auto get(T* = nullptr)
-> typename std::enable_if<std::is_same<U, T>::value, T&>::type
{
return m_member;
}
template <std::size_t N>
auto get(T* = nullptr)
-> typename std::enable_if<N == 0, T&>::type
{
return m_member;
}
private:
T m_member;
};
Tests:
Foo<char, int, bool, double> a{ 'a', 42, true, 1.234 };
assert('a' == a.get<char>());
assert(42 == a.get<int>());
assert(true == a.get<1>());
assert(42 == a.get<2>());
a.get<char>() = 'b';
assert('b' == a.get<3>());
DEMO
For other implementations that provide an access to members see std::tuple<...> with its std::get<N>().
A canonical implementation looks as below:
#include <type_traits>
#include <cstddef>
template <typename... Types>
struct Foo;
template <typename T, typename... Types>
struct Foo<T, Types...> : Foo<Types...>
{
Foo(T member, Types... others) : Foo<Types...>{others...}, m_member{member} {}
T m_member;
};
template <typename T>
struct Foo<T>
{
Foo(T member) : m_member{member} {}
T m_member;
};
template <std::size_t N, typename T>
struct element;
template <typename T, typename... Types>
struct element<0, Foo<T, Types...>>
{
using type = T;
};
template <std::size_t N, typename T, typename... Types>
struct element<N, Foo<T, Types...>>
{
using type = typename element<N - 1, Foo<Types...>>::type;
};
template <std::size_t N, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
-> typename std::enable_if<N == 0, T&>::type
{
return f.m_member;
}
template <std::size_t N, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
-> typename std::enable_if<N != 0
, typename element<N, Foo<T, Types...>>::type&
>::type
{
Foo<Types...>& p = f;
return get<N - 1>(p);
}
template <typename U, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
-> typename std::enable_if<std::is_same<T, U>::value, T&>::type
{
return f.m_member;
}
template <typename U, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
-> typename std::enable_if<!std::is_same<T, U>::value, U&>::type
{
Foo<Types...>& p = f;
return get<U>(p);
}
Tests:
Foo<char, int, bool, double> a{ 'a', 42, true, 1.234 };
assert(true == get<2>(a));
assert(42 == get<int>(a));
get<char>(a) = 'b';
assert('b' == get<0>(a));
DEMO 2

Related

Compiler cannot handle std::invoke

What is the problem with this?
struct foo {
void process(int, char, bool) {}
};
foo myfoo;
template <typename Method> struct thing {
void doit() {
Method m = Method{};
(myfoo.*m)(5, 'a', true);
}
};
int main() {
thing<decltype(&foo::process)> t;
t.doit();
}
I think this isolates the problem. What is the workaround if I have to use the type Method, as in the case of my original post below?
Original post:
In the following attempted test:
struct Foo { int play (char, bool) {return 3;} };
struct Bar { double jump (int, short, float) {return 5.8;} };
struct Baz { char run (double) {return 'b';} };
int main() {
Foo foo; Bar bar; Baz baz;
Functor<decltype(&Foo::play), decltype(&Bar::jump), decltype(&Baz::run)> func;
func(foo, bar, baz, 'c', true, 5, 2, 4.5, 6.8);
}
As you can predict, func is supposed to carry out
foo.play('c', true); bar.jump(5, 2, 4.5); baz.run(6.8);
My implementation of the Functor class so far (ignoring perfect forwarding and such for now) is
template <typename... Members>
struct Functor {
using m = many_members<Members...>;
template <typename... Args>
typename m::return_types operator()(Args... args) const { // perfect forwarding to do later
auto t = std::make_tuple(args...);
auto objects = utilities::tuple_head<sizeof...(Members)>(t);
auto arguments = utilities::extract_subtuple<sizeof...(Members), sizeof...(Args) - sizeof...(Members)>(t);
call(objects, arguments); // Won't compile on GCC 7.2 or clang 6.0.
}
private:
template <typename Tuple1, typename Tuple2>
auto call (Tuple1& objects, const Tuple2& args) const {
std::invoke(typename utilities::nth_element<0, Members...>::type{}, std::get<0>(objects), 'c', true);
}
};
where my last line using std::invoke is just to test the concept before I continue. It however will not compile on either GCC 7.2 or clang 6.0, so I cannot continue with the generalization. Any workaround here, or a completely different implementation altogether?
Here is everything I have so far:
namespace utilities {
template <std::size_t N, typename... Ts>
struct nth_element : std::tuple_element<N, std::tuple<Ts...>> { };
template <std::size_t Skip, std::size_t Take, typename Tuple>
auto extract_subtuple (const Tuple&, std::enable_if_t<(Take == 0)>* = nullptr) {
return std::tuple<>();
}
template <std::size_t Skip, std::size_t Take, typename Tuple>
auto extract_subtuple (const Tuple& tuple, std::enable_if_t<(Take > 0)>* = nullptr) {
return std::tuple_cat (std::make_tuple(std::get<Skip>(tuple)), extract_subtuple<Skip + 1, Take - 1>(tuple));
}
template <std::size_t N, typename Tuple>
auto tuple_head (const Tuple& tuple) {
return extract_subtuple<0, N>(tuple);
}
}
template <typename Rs, typename Ts, typename ArgsPacks, typename AllArgs, typename... Members> struct many_members_h;
template <typename Rs, typename Ts, typename ArgsPacks, typename AllArgs>
struct many_members_h<Rs, Ts, ArgsPacks, AllArgs> {
using return_types = Rs;
using classes = Ts;
using args_packs = ArgsPacks;
using all_args = AllArgs;
};
template <typename... Rs, typename... Ts, typename... ArgsPacks, typename... AllArgs, typename R, typename T, typename... Args, typename... Rest>
struct many_members_h<std::tuple<Rs...>, std::tuple<Ts...>, std::tuple<ArgsPacks...>, std::tuple<AllArgs...>, R(T::*)(Args...), Rest...> :
many_members_h<std::tuple<Rs..., R>, std::tuple<Ts..., T>, std::tuple<ArgsPacks..., std::tuple<Args...>>, std::tuple<AllArgs..., Args...>, Rest...> { };
template <typename... Members>
struct many_members : many_members_h<std::tuple<>, std::tuple<>, std::tuple<>, std::tuple<>, Members...> { };
template <typename... Members>
struct Functor {
using m = many_members<Members...>;
template <typename... Args>
typename m::return_types operator()(Args... args) const { // perfect forwarding to do later
auto t = std::make_tuple(args...);
auto objects = utilities::tuple_head<sizeof...(Members)>(t);
auto arguments = utilities::extract_subtuple<sizeof...(Members), sizeof...(Args) - sizeof...(Members)>(t);
call(objects, arguments); // Won't compile on GCC 7.2 or clang 6.0.
}
private:
template <typename Tuple1, typename Tuple2>
auto call (Tuple1& objects, const Tuple2& args) const {
std::invoke(typename utilities::nth_element<0, Members...>::type{}, std::get<0>(objects), 'c', true);
}
};
// Testing
#include <iostream>
struct Foo { int play (char, bool) {return 3;} };
struct Bar { double jump (int, short, float) {return 5.8;} };
struct Baz { char run (double) {return 'b';} };
int main() {
Foo foo; Bar bar; Baz baz;
Functor<decltype(&Foo::play), decltype(&Bar::jump), decltype(&Baz::run)> func;
func(foo, bar, baz, 'c', true, 5, 2, 4.5, 6.8);
}
Taking your smaller first example, note that decltype(&foo::process) is the type called void (foo::*)(int, char, bool).
This type does not contain or imply any association with the original function foo::process itself. Just like the type int doesn't let you get the value of some particular int elsewhere in your program, or the type SomeClass doesn't let you refer to a SomeClass object elsewhere in your program, the type alone doesn't carry a value or identity.
The expression Method{} value-initializes this pointer to member type. Which means the resulting value is a null pointer value. Which means calling it is undefined behavior (and on many systems is likely to result in a segfault).
If you're using C++17 mode, you could use a template <auto Method> non-type parameter and simply pass &foo::process (without using decltype) as the template argument. Some SFINAE techniques could enforce that the argument is actually a pointer to member function, and some helper traits could be used to get the class type and parameter list tuple.
Or if you're using a standard earlier than C++17, you'll have to either make the function pointer a function argument, or make it a template parameter which follows the type, as in template <typename MethodType, MethodType Method>, then call as thing<decltype(&foo::process), &foo::process>.
Thanks to aschepler's answer and advice to use auto... instead of typename... for the member function pointers, I was able to carry the original goal:
#include <tuple>
#include <functional> // std::invoke
#include <type_traits>
#include <utility>
namespace utilities {
template <std::size_t N, auto I, auto... Is>
struct nth_element : nth_element<N - 1, Is...> { };
template <auto I, auto... Is>
struct nth_element<0, I, Is...> {
static constexpr decltype(I) value = I;
};
template <std::size_t N, typename Pack> struct nth_index;
template <std::size_t N, std::size_t... Is>
struct nth_index<N, std::index_sequence<Is...>> : nth_element<N, Is...> { };
template <std::size_t Skip, std::size_t Take, typename Tuple>
auto extract_subtuple (const Tuple&, std::enable_if_t<(Take == 0)>* = nullptr) {
return std::tuple<>();
}
template <std::size_t Skip, std::size_t Take, typename Tuple>
auto extract_subtuple (const Tuple& tuple, std::enable_if_t<(Take > 0)>* = nullptr) {
return std::tuple_cat (std::make_tuple(std::get<Skip>(tuple)), extract_subtuple<Skip + 1, Take - 1>(tuple));
}
template <std::size_t N, typename Tuple>
auto tuple_head (const Tuple& tuple) {
return extract_subtuple<0, N>(tuple);
}
template <typename F, typename T, typename Tuple, std::size_t... Is>
decltype(auto) invoke_with_tuple_h (F&& f, T&& t, Tuple&& tuple, std::index_sequence<Is...>&&) {
return std::invoke(std::forward<F>(f), std::forward<T>(t), std::get<Is>(std::forward<Tuple>(tuple))...);
}
template <typename F, typename T, typename Tuple>
decltype(auto) invoke_with_tuple (F&& f, T&& t, Tuple&& tuple) {
return invoke_with_tuple_h (std::forward<F>(f), std::forward<T>(t), std::forward<Tuple>(tuple), std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{});
}
template <typename PartialSums, std::size_t Sum, std::size_t... Is> struct all_partial_sums_h;
template <std::size_t... PartialSums, std::size_t Sum>
struct all_partial_sums_h<std::index_sequence<PartialSums...>, Sum> {
using type = std::index_sequence<PartialSums..., Sum>;
using type_without_last_sum = std::index_sequence<PartialSums...>; // We define this because this is what we need actually.
};
template <std::size_t... PartialSums, std::size_t Sum, std::size_t First, std::size_t... Rest>
struct all_partial_sums_h<std::index_sequence<PartialSums...>, Sum, First, Rest...> :
all_partial_sums_h<std::index_sequence<PartialSums..., Sum>, Sum + First, Rest...> { };
template <typename Pack> struct all_partial_sums;
template <std::size_t... Is>
struct all_partial_sums<std::index_sequence<Is...>> : all_partial_sums_h<std::index_sequence<>, 0, Is...> { };
template <typename Pack> struct pack_size;
template <template <typename...> class P, typename... Ts>
struct pack_size<P<Ts...>> : std::integral_constant<std::size_t, sizeof...(Ts)> { };
template <typename PackOfPacks> struct get_pack_sizes;
template <template <typename...> class P, typename... Packs>
struct get_pack_sizes<P<Packs...>> {
using type = std::index_sequence<pack_size<Packs>::value...>;
};
}
template <typename Method> struct method_traits;
template <typename R, typename C, typename... Args>
struct method_traits<R(C::*)(Args...)> {
using return_type = R;
using class_type = C;
using args_type = std::tuple<Args...>;
};
template <typename Rs, typename Cs, typename ArgsPacks, auto... Members> struct many_members_h;
template <typename Rs, typename Cs, typename ArgsPacks>
struct many_members_h<Rs, Cs, ArgsPacks> {
using return_types = Rs;
using classes = Cs;
using args_packs = ArgsPacks;
};
template <typename... Rs, typename... Cs, typename... ArgsPacks, auto F, auto... Rest>
struct many_members_h<std::tuple<Rs...>, std::tuple<Cs...>, std::tuple<ArgsPacks...>, F, Rest...> :
many_members_h<std::tuple<Rs..., typename method_traits<decltype(F)>::return_type>, std::tuple<Cs..., typename method_traits<decltype(F)>::class_type>, std::tuple<ArgsPacks..., typename method_traits<decltype(F)>::args_type>, Rest...> { };
template <auto... Members>
struct many_members : many_members_h<std::tuple<>, std::tuple<>, std::tuple<>, Members...> { };
template <auto... Members>
struct Functor {
using m = many_members<Members...>;
using starting_points = typename utilities::all_partial_sums<typename utilities::get_pack_sizes<typename m::args_packs>::type>::type;
template <typename... Args>
typename m::return_types operator()(Args&&... args) const {
constexpr std::size_t M = sizeof...(Members);
auto t = std::make_tuple(std::forward<Args>(args)...);
auto objects = utilities::tuple_head<M>(t);
auto arguments = utilities::extract_subtuple<M, sizeof...(Args) - M>(t);
return call(objects, arguments, std::make_index_sequence<M>{});
}
private:
template <typename Tuple1, typename Tuple2, std::size_t... Is>
auto call (Tuple1& objects, const Tuple2& args, std::index_sequence<Is...>&&) const { // perfect forwarding to do later
return std::make_tuple(call_helper<Is>(objects, args)...);
}
template <std::size_t N, typename Tuple1, typename Tuple2>
auto call_helper (Tuple1& objects, const Tuple2& args) const { // perfect forwarding to do later
constexpr std::size_t s = std::tuple_size_v<std::tuple_element_t<N, typename m::args_packs>>;;
constexpr std::size_t a = utilities::nth_index<N, starting_points>::value;
const auto args_tuple = utilities::extract_subtuple<a, s>(args);
return utilities::invoke_with_tuple (utilities::nth_element<N, Members...>::value, std::get<N>(objects), args_tuple);
}
};
// Testing
#include <iostream>
struct Foo { int play (char c, bool b) { std::cout << std::boolalpha << "Foo::play(" << c << ", " << b << ") called.\n"; return 3; } };
struct Bar { double jump (int a, short b, float c) { std::cout << "Bar::jump(" << a << ", " << b << ", " << c << ") called.\n"; return 5.8; } };
struct Baz { char run (double d) { std::cout << "Baz::run(" << d << ") called.\n"; return 'b'; } };
int main() {
Foo foo; Bar bar; Baz baz;
Functor<&Foo::play, &Bar::jump, &Baz::run> func;
const auto tuple = func(foo, bar, baz, 'c', true, 5, 2, 4.5, 6.8);
std::cin.get();
}
Output:
Baz::run(6.8) called.
Bar::jump(5, 2, 4.5) called.
Foo::play(c, true) called.

C++ template mechanism to get the number of function arguments, which would work for lambdas and normal functions

I am trying to implement a mechanism, which would provide me some information about the template argument function type.
Main idea is to get the number of arguments, return type, total sum of sizes of each argument.
I have something running for lambdas based on this entry.
template <typename T, typename... Args>
struct sumSizeOfArgs {
enum { totalSize = sizeof(typename std::decay<T>::type) + sumSizeOfArgs<Args...>::totalSize };
};
template<typename T>
struct sumSizeOfArgs<T> {
enum {totalSize = sizeof(typename std::decay<T>::type)};
};
}
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
enum { arity = sizeof...(Args) };
typedef ReturnType result_type;
enum { totalSize = sumSizeOfArgs<Args...>::totalSize };
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};
However, indeed this code does not work for normal functions types such as
function_traits<void()>
it does not have an operator(). I would greatly appreciate, any suggestion to make this code work for both cases.
Thanks,
Slightly improved original part:
#include <tuple>
#include <type_traits>
template <typename... Args>
struct sumSizeOfArgs
{
static constexpr size_t totalSize = 0;
};
template <typename T, typename... Args>
struct sumSizeOfArgs<T, Args...>
{
static constexpr size_t totalSize = sizeof(typename std::decay<T>::type)
+ sumSizeOfArgs<Args...>::totalSize;
};
template <typename T>
struct sumSizeOfArgs<T>
{
static constexpr size_t totalSize = sizeof(typename std::decay<T>::type);
};
template <typename T>
struct function_traits_impl;
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...)>
{
static constexpr size_t arity = sizeof...(Args);
using result_type = ReturnType;
static constexpr size_t totalSize = sumSizeOfArgs<Args...>::totalSize;
template <size_t i>
struct arg
{
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...) const>
: function_traits_impl<ReturnType(ClassType::*)(Args...)> {};
New part starts here (traits' class partial specialization for functions):
template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(Args...)>
{
static constexpr size_t arity = sizeof...(Args);
using result_type = ReturnType;
static constexpr size_t totalSize = sumSizeOfArgs<Args...>::totalSize;
template <size_t i>
struct arg
{
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(*)(Args...)>
: function_traits_impl<ReturnType(Args...)> {};
Crucial part is here (determining the presence of operator()):
template <typename T, typename V = void>
struct function_traits
: function_traits_impl<T> {};
template <typename T>
struct function_traits<T, decltype((void)&T::operator())>
: function_traits_impl<decltype(&T::operator())> {};
Test:
int main()
{
static_assert(function_traits<void()>::arity == 0, "!");
static_assert(function_traits<void(int)>::arity == 1, "!");
static_assert(function_traits<void(*)(int, float)>::arity == 2, "!");
auto lambda = [] (int, float, char) {};
static_assert(function_traits<decltype(lambda)>::arity == 3, "!");
auto mutable_lambda = [] (int, float, char, double) mutable {};
static_assert(function_traits<decltype(mutable_lambda)>::arity == 4, "!");
}
DEMO 1
Or even simpler, with a single trait class:
#include <tuple>
template <typename ReturnType, typename... Args>
struct function_traits_defs
{
static constexpr size_t arity = sizeof...(Args);
using result_type = ReturnType;
template <size_t i>
struct arg
{
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
template <typename T>
struct function_traits_impl;
template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(Args...)>
: function_traits_defs<ReturnType, Args...> {};
template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(*)(Args...)>
: function_traits_defs<ReturnType, Args...> {};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...)>
: function_traits_defs<ReturnType, Args...> {};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...) const>
: function_traits_defs<ReturnType, Args...> {};
// + other cv-ref-variations
template <typename T, typename V = void>
struct function_traits
: function_traits_impl<T> {};
template <typename T>
struct function_traits<T, decltype((void)&T::operator())>
: function_traits_impl<decltype(&T::operator())> {};
int main()
{
static_assert(function_traits<void()>::arity == 0, "!");
static_assert(function_traits<void(int)>::arity == 1, "!");
static_assert(function_traits<void(*)(int, float)>::arity == 2, "!");
auto lambda = [] (int, float, char) {};
static_assert(function_traits<decltype(lambda)>::arity == 3, "!");
auto mutable_lambda = [] (int, float, char, double) mutable {};
static_assert(function_traits<decltype(mutable_lambda)>::arity == 4, "!");
struct Functor
{
void operator()(int) {}
};
static_assert(function_traits<Functor>::arity == 1, "!");
}
DEMO 2
Note: Unfortunately none of the above solutions will work for generic lambdas, related discussion is Arity of a generic lambda

Variadic templates and Alexandrescu tuple implementation

I try to learn a little bit about template metaprogramming and
currently i play around with variadic templates.
In his talk "Variadic Templates are Funadic" Alexandrescu introduces a
small tuple implementation, which i try to build and maybe extend a
little bit. (I know it is a toy example, i just try to learn a little
bit more about c++). However, i have a small problem with his code.
Here it is:
template <typename... Ts>
class tuple
{};
template<size_t, typename> struct tuple_element;
template<typename T, typename... Ts>
struct tuple_element<0, tuple<T, Ts...>>
{
typedef T type;
};
template <size_t k, typename T, typename... Ts>
struct tuple_element<k, tuple<T, Ts...>>
{
typedef
typename tuple_element<k-1,tuple<Ts...>>::type type;
};
template<size_t k, typename... Ts>
typename std::enable_if<k == 0,
typename tuple_element<0,tuple<Ts...>>::type&>::type
get(tuple<Ts...>& t)
{return t.head_;}
template<size_t k, typename T, typename... Ts>
typename std::enable_if<k != 0,
typename tuple_element<k,tuple<T,Ts...>>::type&>::type
get(tuple<T,Ts...>& t)
{
tuple<Ts...> & super = t;
return get<k-1>(super);
}
template <typename T, typename... Ts>
class tuple<T,Ts...> : private tuple<Ts...>
{
private:
T head_;
};
int main(int argc, char *argv[])
{
tuple<int,std::string> t;
get<0>(t) = 10;
get<1>(t) = std::string("test");
std::cout<<get<0>(t)<<std::endl;
}
In order to work correctly, the get function must be friend of the
tuple class (It is also mentioned on this slides, see 32). But how
does the friend declaration looks like? I tried different approaches
but could not get it to work. When i change the code from private to public inheritance
and change the access rules for head_ to public it works.
Thanks for your help
Kevin
This works for me:
template <typename T, typename... Ts>
class tuple<T,Ts...> : private tuple<Ts...>
{
private:
T head_;
template<size_t k, typename T1, typename... T1s>
friend typename std::enable_if<k != 0,
typename tuple_element<k,tuple<T1,T1s...>>::type&>::type
get(tuple<T1,T1s...>& t);
template<size_t k, typename... T1s>
friend typename std::enable_if<k == 0,
typename tuple_element<0,tuple<T1s...>>::type&>::type
get(tuple<T1s...>& t);
};
Demo.
Another implementation from the other point of view:
#include <iostream>
#include <type_traits>
template <class... Args>
class Tuple;
template <>
class Tuple<> {};
template <class T, class... Args>
class Tuple<T, Args...>: public Tuple<Args...> {
using Base = Tuple<Args...>;
T Value_;
public:
Tuple(T&& value, Args&&... args)
: Value_(std::forward<T>(value))
, Base(std::forward<Args>(args)...)
{
}
T& Value() {
return Value_;
}
};
template <size_t k, class T, class... Args>
struct Select {
using Type = typename Select<k - 1, Args...>::Type;
};
template <class T, class... Args>
struct Select<0, T, Args...> {
using Type = T;
};
template <size_t k, class... Args>
using TSelect = typename Select<k, Args...>::Type;
template <bool P, class T>
using TEnableIf = typename std::enable_if<P, T>::type;
template <size_t k, class T, class... Args>
TEnableIf<(k != 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) {
return get<k - 1, Args...>(t);
}
template <size_t k, class T, class... Args>
TEnableIf<(k == 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) {
return t.Value();
}
int main() {
Tuple<int, char> t(1, 'a');
std::cout << get<0>(t) << std::endl;
std::cout << get<1>(t) << std::endl;
get<1>(t) = 'b';
std::cout << get<1>(t) << std::endl;
}
Actually, we don't need a Tuple to get a type.

"Manual" signature overload resolution

I want to make a std::function like object that can handle storing more than one overload.
Syntax sort of like this: my_function< int(double, int), double(double, double), char(int, int) >.
Or, more explicitly:
template<typename... Ts>
struct type_list {};
template<typename... Signatures >
struct my_function {
std::tuple< std::function<Signatures>... > m_functions;
typedef type_list< Signatures... > sig_list;
template<typename... Args>
typename pick_overload_signature< sig_list, type_list<Args...> >::return_value
operator()( Args&&... args )
{
return get<pick_overload_signature< sig_list, type_list<Args...> >::index>(m_functions)(std::forward<Args>(args)...);
}
};
My question: how should I write pick_overload_signatures?
Here is the work I've done on it:
My inclination would be to write a partial order on function signatures with respect to a given set of arguments, then sort the type list of function signatures, then grab the best (with possibly a compile-time assert that the best one is unique). To pull that off, I'd have to have a solid partial order (with respect to a set of arguments passed in) on function signatures...
13.3.3.1 tells me how to determine if there is a valid conversion. I can cheat for this by using the compiler to do a conversion for me, and use SFINAE to detect if it occurred for a given argument passed in and the signature of one of the "overloads".
13.3.3.2 tells me how to order these conversions. Here I have to detect if a conversion sequence is user defined or a standard sequence. I am not sure how to distinguish between the two.
Maybe I can use traits class to detect the existence of user-defined conversions sequences. Check for the existence of &S::operator D() and &D::D(S const&) and &D::D(S) and &D::D(S&&) or something like that.
has_user_defined_conversion<S,D>::value, has_standard_conversion<S,D>::value, etc?
Will this approach work, has someone already done it, or has someone already done parts of this?
Result of Answers
#include <type_traits>
#include <cstddef>
#include <utility>
#include <functional>
#include <tuple>
#include <string>
// Packaged list of types:
template<typename... Ts>
struct type_list {
template<template<typename...>class target>
struct apply {
typedef target<Ts...> type;
};
template<typename T>
struct append {
typedef type_list< Ts..., T > type;
};
template<typename T>
struct prepend {
typedef type_list< T, Ts... > type;
};
};
template<template<typename>class mapper, typename list>
struct map_types {
typedef type_list<> type;
};
template<template<typename>class mapper, typename T0, typename... Ts>
struct map_types<mapper, type_list<T0, Ts...>> {
typedef typename map_types<mapper, type_list<Ts...>>::type tail;
typedef typename tail::template prepend< typename mapper<T0>::type >::type type;
};
template<template<typename>class mapper, typename list>
using MapTypes = typename map_types<mapper, list>::type;
template<template<typename>class temp>
struct apply_template_to {
template<typename T>
struct action {
typedef temp<T> type;
};
};
template<template<typename> class temp, typename list>
struct apply_to_each:map_types< apply_template_to<temp>::template action, list > {};
template<template<typename> class temp, typename list>
using ApplyToEach = typename apply_to_each<temp, list>::type;
template<std::size_t n, typename list>
struct nth_type {};
template<std::size_t n, typename first, typename... elements>
struct nth_type<n, type_list<first, elements...>>:nth_type<n-1, type_list<elements...>>
{};
template<typename first, typename... elements>
struct nth_type<0, type_list<first, elements...>>
{
typedef first type;
};
template<std::size_t n, typename list>
using NthType = typename nth_type<n, list>::type;
// func data
template<typename R, typename... Args>
struct unpacked_func {
typedef R result_type;
typedef type_list<Args...> args_type;
typedef unpacked_func< R, Args... > unpacked_type;
template<template<typename>class target>
struct apply {
typedef target<R(Args...)> type;
};
};
namespace unpack_details {
// Extracting basic function properties:
template<typename Func>
struct unpack_func {};
template<typename R, typename... Args>
struct unpack_func< R(Args...) > {
typedef unpacked_func< R, Args... > type;
};
template<typename R, typename... Args>
struct unpack_func< unpacked_func<R, Args...> >:
unpack_func< R(Args...) >
{};
}
template<typename Func>
using FuncUnpack = typename unpack_details::unpack_func<Func>::type;
template<typename Func>
struct func_props:func_props<FuncUnpack<Func>> {};
template<typename R, typename... Args>
struct func_props<unpacked_func<R, Args...>>:
unpacked_func<R, Args...>
{};
template<typename Func>
using FuncResult = typename func_props<Func>::result_type;
template<typename Func>
using FuncArgs = typename func_props<Func>::args_type;
template<typename Func>
struct make_func_ptr:make_func_ptr<FuncUnpack<Func>> {};
template<typename R, typename... Args>
struct make_func_ptr< unpacked_func< R, Args... > > {
typedef R(*type)(Args...);
};
template<typename Func>
using MakeFuncPtr = typename make_func_ptr<Func>::type;
// Marking a type up with an index:
template<typename R, std::size_t i>
struct indexed_type {
typedef R type;
enum { value = i };
};
// Sequences of size_t:
template<std::size_t... s>
struct seq {};
template<std::size_t min, std::size_t max, std::size_t... s>
struct make_seq: make_seq< min, max-1, max-1, s...> {};
template<std::size_t min, std::size_t... s>
struct make_seq< min, min, s...> {
typedef seq<s...> type;
};
template<std::size_t max, std::size_t min=0>
using MakeSeq = typename make_seq<max, min>::type;
namespace overload_details {
template<std::size_t n, typename... Overloads>
struct indexed_linear_signatures {};
template<typename Overload>
struct signature_generator {};
template<typename R, typename... Args>
struct signature_generator<unpacked_func<R, Args...>> {
R operator()(Args...); // no impl
};
template<typename Func, std::size_t i>
struct indexed_retval {};
template<typename R, typename... Args, std::size_t i>
struct indexed_retval< unpacked_func<R, Args...>, i > {
typedef unpacked_func<indexed_type<R,i>, Args...> type;
};
template<typename Func, std::size_t i>
using IndexRetval = typename indexed_retval<Func,i>::type;
void test1() {
typedef overload_details::IndexRetval< FuncUnpack<void()>, 0 > indexed;
indexed::apply<std::function>::type test = []()->indexed_type<void,0> {return indexed_type<void,0>();};
}
template<std::size_t n, typename Overload, typename... Overloads>
struct indexed_linear_signatures<n, Overload, Overloads...>:
signature_generator<IndexRetval<FuncUnpack<Overload>,n>>,
indexed_linear_signatures<n+1, Overloads...>
{};
template<typename T>
struct extract_index {};
template<typename T, std::size_t i>
struct extract_index<indexed_type<T,i>> {
enum {value = i};
};
template<typename T>
using Decay = typename std::decay<T>::type;
template<typename indexed_overloads, typename... Args>
struct get_overload_index {
enum{ value = extract_index< Decay<decltype( std::declval<indexed_overloads>()(std::declval<Args>()...) )> >::value };
};
template<typename Overloads, typename Args>
struct get_overload {};
template<typename... Overloads, typename... Args>
struct get_overload<type_list<Overloads...>, type_list<Args...>> {
typedef indexed_linear_signatures<0, Overloads...> sig_index;
enum { index = get_overload_index< sig_index, Args... >::value };
typedef FuncUnpack< NthType<index, type_list<Overloads...> > > unpacked_sig;
};
template<typename Overloads, typename Args>
using GetOverloadSig = typename get_overload< Overloads, Args >::unpacked_sig;
}
template<typename Overloads, typename Arguments>
struct pick_overload_signature {
enum{ index = overload_details::get_overload<Overloads, Arguments>::index };
typedef overload_details::GetOverloadSig<Overloads, Arguments> unpacked_sig;
};
#include <iostream>
void test1() {
typedef type_list< void(int), void(double) > overloads;
typedef type_list< int > args;
typedef pick_overload_signature< overloads, args > result;
std::cout << result::index << " should be 0\n";
typedef type_list< double > args2;
typedef pick_overload_signature< overloads, args2 > result2;
std::cout << result2::index << " should be 1\n";
// ;
typedef ApplyToEach< std::function, overloads >::apply< std::tuple >::type functions;
typedef std::tuple< std::function<void(int)>, std::function<void(double)> > functions0;
std::cout << std::is_same<functions, functions0>() << " should be true\n";
functions funcs{
[](int) { std::cout << "int!" << "\n"; },
[](double) { std::cout << "double!" << "\n"; }
};
std::get<result::index>(funcs)(0);
}
template< typename... Signatures >
struct my_function {
typedef type_list<Signatures...> signatures;
typedef std::tuple< std::function<Signatures>... > func_tuple;
func_tuple functions;
template<typename... Funcs>
explicit my_function(Funcs&&... funcs):
functions( std::forward<Funcs>(funcs)... )
{}
template<typename... Args>
auto
operator()(Args&&... args) const ->
typename overload_details::GetOverloadSig< signatures, type_list<Args...> >::result_type
{
return std::get<
pick_overload_signature< signatures, type_list<Args...> >::index
>(functions)(std::forward<Args>(args)...);
}
// copy/assign boilerplate
template<typename... OtherSignatures>
my_function( my_function<OtherSignatures...> const& o ):
functions( o.functions )
{}
template<typename... OtherSignatures>
my_function( my_function<OtherSignatures...> && o ):
functions( std::move(o.functions) )
{}
template<typename... OtherSignatures>
my_function& operator=( my_function<OtherSignatures...> const& o )
{
functions = o.functions;
return *this;
}
template<typename... OtherSignatures>
my_function& operator=( my_function<OtherSignatures...> && o ) {
functions = std::move(o.functions);
return *this;
}
};
struct printer {
template<typename T>
void operator()( T const& t ) {
std::cout << t << "\n";
}
};
void print(int x) {
std::cout << "int is " << x << "\n";
}
void print(std::string s) {
std::cout << "string is " << s << "\n";
}
void test2() {
my_function< void(int), void(std::string) > funcs{
[](int x){ std::cout << "int is " << x << "\n";},
[](std::string s){ std::cout << "string is " << s << "\n";}
};
std::cout << "test2\n";
funcs("hello");
funcs(0);
my_function< void(int), void(std::string) > funcs2{
printer(), printer()
};
funcs2("hello");
funcs2(12.7);
// doesn't work:
/*
my_function< void(int), void(std::string) > funcs3{
print,
print
};
*/
}
void test3() {
}
int main() {
test1();
test2();
test3();
}
Isn't done, but is usable.
Thanks all!
i'm sure it is doable your way, but may be you will be satisfied with this one https://gist.github.com/dabrahams/3779345
template<class...Fs> struct overloaded;
template<class F1, class...Fs>
struct overloaded<F1, Fs...> : F1, overloaded<Fs...>::type
{
typedef overloaded type;
overloaded(F1 head, Fs...tail)
: F1(head),
overloaded<Fs...>::type(tail...)
{}
using F1::operator();
using overloaded<Fs...>::type::operator();
};
template<class F>
struct overloaded<F> : F
{
typedef F type;
using F::operator();
};
template<class...Fs>
typename overloaded<Fs...>::type overload(Fs...x)
{ return overloaded<Fs...>(x...); }
auto f = overload(
[](int x) { return x+1; },
[](char const* y) { return y + 1; },
[](int* y) { return y; });
I think you can use something like these traits... But if you want make overloading resolution fully as in standard - you need more code http://en.cppreference.com/w/cpp/language/implicit_cast
#include <type_traits>
template<typename T, typename D>
struct is_constructible
{
template<typename C, typename F>
static auto test(C*) -> decltype(C(std::declval<F>()), std::true_type());
template<typename, typename>
static std::false_type test(...);
static const bool value = std::is_class<T>::value &&
std::is_same<std::true_type, decltype(test<T, D>(0))>::value;
};
template<typename T, typename D>
struct has_conversion_operator
{
static std::true_type test(D d);
template<typename C, typename F>
static auto test(C* c) -> decltype(test(*c));
template<typename, typename>
static std::false_type test(...);
static const bool value = std::is_class<T>::value &&
!is_constructible<T, D>::value &&
std::is_same<std::true_type, decltype(test<T, D>(0))>::value;
};
template<typename T, typename D>
struct is_standard_convertible :
std::integral_constant<bool, !has_conversion_operator<T, D>::value &&
!is_constructible<T, D>::value &&
std::is_convertible<T, D>::value>
{
};
template<typename T, typename D>
struct is_user_convertible :
std::integral_constant<bool, has_conversion_operator<T, D>::value ||
is_constructible<T, D>::value>
{
};
and implement what you want like:
first check, that signatures are standard_convertible
if not check that signature are user_convertible.

Generalizing for_each over a tuple to accept a variable number of arguments

Currently, I have:
template <unsigned I,
unsigned N,
typename Tuple,
typename UnaryFunction>
struct for_;
template <unsigned N, typename Tuple, typename UnaryFunction>
struct for_<N, N, Tuple, UnaryFunction> {
static
void call(const Tuple&, UnaryFunction) {}
};
template <unsigned I,
unsigned N,
typename Tuple,
typename UnaryFunction>
struct for_ {
static
void call(Tuple&& x, UnaryFunction f) {
f(get<I>(x));
for_<I + 1, N, Tuple, UnaryFunction>::call(std::forward<Tuple>(x), f);
}
};
template <typename Tuple, typename UnaryFunction>
inline
void for_each(Tuple&& x, UnaryFunction f) {
for_<0,
tuple_size<
typename std::remove_const<
typename std::remove_reference<Tuple>::type
>::type
>::value,
Tuple,
UnaryFunction>::call(std::forward<Tuple>(x), f);
}
Is it possible to generalize this, probably by variadic templates, to take any number of tuple arguments?
EDIT:
Here is how I would use what I am unable to define:
if (i != e) {
std::array<Tuple, 2> x;
std::get<0>(x) = *i;
std::get<1>(x) = *i;
++i;
std::for_each (i, e, [&x](const Tuple& y) {
for_each(std::get<0>(x), y, assign_if(std::less));
for_each(std::get<1>(x), y, assign_if(std::greater));
});
}
EDIT: changed to use rvalue references and std::forward
I'm not sure is it what you expected, but I'll post it - maybe someone will find it helpful.
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>
F for_each(const Tuple& t, F f) {
for_each_impl<tuple_size<Tuple>::value - 1, Tuple, F>::for_each(t, f);
return f;
}
}
Functor:
struct call_tuple_item {
template<typename T>
void operator()(T a) {
std::cout << "call_tuple_item: " << a << std::endl;
}
};
Main function:
std::tuple<float, const char*> t1(3.14, "helloworld");
std::for_each(t1, call_tuple_item());
You can check my answer here for a hint on expanding tuples
How do I expand a tuple into variadic template function's arguments?
See below for the map(UnaryFunction, Tuple&&...) implementation I will be using, as well as the code I had been messing with in an attempt to get it working completely as I wanted (for_aux, last, etc.).
#include <array>
#include <iostream>
#include <tuple>
namespace detail {
struct static_ {
private:
static_() = delete;
static_(const static_&) = delete;
static_& operator=(const static_&) = delete;
};
template <unsigned... Args>
struct max;
template <unsigned Head, unsigned... Tail>
struct max<Head, Tail...>: private static_ {
static const unsigned value = Head > max<Tail...>::value
? Head
: max<Tail...>::value;
};
template <>
struct max<>: private static_ {
static const unsigned value = 0;
};
template <unsigned... Args>
struct min;
template <unsigned Head, unsigned... Tail>
struct min<Head, Tail...>: private static_ {
static const unsigned value = Head < min<Tail...>::value
? Head
: min<Tail...>::value;
};
template <>
struct min<>: private static_ {
static const unsigned value = 0;
};
template <typename... Args>
struct for_aux;
template <typename A, typename B>
struct for_aux<A, B>: private static_ {
static
void call(A&& a, B b) {
b(std::forward(a));
}
};
template <typename A, typename B, typename C>
struct for_aux<A, B, C>: private static_ {
static
void call(A&& a, B&& b, C c) {
c(std::forward(a), std::forward(b));
}
};
template <typename A, typename B, typename C, typename D>
struct for_aux<A, B, C, D>: private static_ {
static
void call(A&& a, B&& b, C&& c, D d) {
d(std::forward(a), std::forward(b), std::forward(c));
}
};
// template <typename Head, typename... Tail>
// struct for_aux: private static_ {
// static
// void call(Tail&&... x, Head f) {
// f(std::forward(x)...);
// }
// };
template <typename... Args>
struct last;
template <typename X>
struct last<X>: private static_ {
typedef X type;
};
template <typename Head, typename... Tail>
struct last<Head, Tail...>: private static_ {
typedef typename last<Tail...>::type type;
};
template <unsigned I,
unsigned N,
typename UnaryFunction,
typename... Tuples>
struct map;
template <unsigned N, typename UnaryFunction, typename... Tuples>
struct map<N, N, UnaryFunction, Tuples...>: private static_ {
static
void call(UnaryFunction, const Tuples&...) {}
};
template <unsigned I,
unsigned N,
typename UnaryFunction,
typename... Tuples>
struct map: private static_ {
static
void call(UnaryFunction f, Tuples&&... x) {
f(std::get<I>(std::forward<Tuples>(x))...);
map<I + 1,
N,
UnaryFunction,
Tuples...>::call(f, std::forward<Tuples>(x)...);
}
};
template <typename Tuple>
struct tuple_size: private static_ {
enum {
value = std::tuple_size<
typename std::remove_const<
typename std::remove_reference<Tuple>::type
>::type
>::value
};
};
}
template <typename UnaryFunction, typename... Tuples>
inline
void map(UnaryFunction f, Tuples&&... x) {
detail::map<0,
detail::max<
detail::tuple_size<Tuples>::value...
>::value,
UnaryFunction,
Tuples...
>::call(f, std::forward<Tuples>(x)...);
}
using namespace std;
struct f {
template <typename T, typename U>
void operator()(const T& i, const U& j) {
cout << i << " " << j << endl;
}
};
int main() {
const array<int, 2> x = {{2}};
const tuple<double, char> y(1.1, 'a');
map(f(), x, y);
}