I understand why do we need decltype(auto) and it's difference from auto , but I can't get why and when I should/need to use decltype(expression). In all examples on cppreference I can just use decltype(auto), I checked it.
Thanks in advance for your help.
The simplest example I could come up with is this:
void foo(int i) {
for (decltype(i) j = 0; j < i; ++j)
...
}
Here, the index j automatically has the same type as the upper bound i.
An alternative example is provided by a lambda expression:
[](auto i) {
for (decltype(i) j = 0; j < i; ++j)
...
}
but I can't get why and when I should/need to use decltype(expression)
In C++11 you can use trailing return types but not auto-deduced return types. E.g.:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) { return t + u; }
C++14 equivalent is:
template<typename T, typename U>
decltype(auto) add(T t, U u) { return t + u; }
Another use is SFINAE, e.g. detecting existence of a member function with a specific name:
#include <iostream>
template<class T>
auto test_has_f(T* p) -> decltype(static_cast<void>(p->f()), std::true_type{}); // Cast to void to avoid user-defined operator,(), if any.
std::false_type test_has_f(void*);
template<class T>
using HasF = decltype(test_has_f(static_cast<T*>(0)));
struct A {};
struct B { void f(); };
int main() {
std::cout << HasF<A>::value << '\n'; // Outputs 0.
std::cout << HasF<B>::value << '\n'; // Outputs 1.
}
Sometimes you need to declare a type which is related to another type but want to keep it agnostic:
struct foo
{
std::vector<int> data;
decltype(data)::iterator it;
};
Related
I want to have a template like:
template<typename T, class U, U SOME_NON_TYPE_ARG>
func1()
{
if SOME_NON_TYPE_ARG is given
{
// do something special
}
// do something with the SOME_NON_TYPE_ARG value.
}
I want the function body depends on if the SOME_NON_TYPE_ARG is given or not.
I try to make the U to be std::optional, but apparently the optional cannot be the type of non-type template parameters. Is there any way I can achieve this in C++17?
Here is one of my work around, but this is more like a hack, is there any better way to do this?
#include <type_traits>
#include <iostream>
template<typename T> constexpr std::optional<T> typed_nullopt = std::nullopt;
template <typename T, class U = const std::optional<T> &, U SOME_NON_TYPE_ARG = typed_nullopt<T> >
void test_optional_template(T a)
{
if constexpr (SOME_NON_TYPE_ARG == typed_nullopt<T>)
{
std::cout << a << " we do not have non-type arg" << std::endl;
}
else
{
std::cout << a + SOME_NON_TYPE_ARG << std::endl;
}
}
int main()
{
test_optional_template<int, int, 3>(5);
test_optional_template<int>(10);
}
The output will be:
8
10 we do not have non-type arg
Overload the function:
template<typename T, class U>
void func1()
{
// Do something
}
template<typename T, class U, U SOME_NON_TYPE_ARG>
void func1()
{
// Do something else
func1<T, U>();
}
You can do this:
template <typename T, auto... Vs>
void func() {
static_assert(sizeof...(Vs) <= 1);
if constexpr (sizeof...(Vs) == 1) {
constexpr auto V = [](auto X){ return X; }(Vs...);
// do something with V
}
}
func<int>() won't do anything special, func<int, 1>() will pull out V as 1, func<int, 1, 2>() is ill-formed.
I would like to understand where I am going wrong in trying to minimize the verbosity of my member functions template specialization. I get compilation errors when doing so rather arbitrarily. Here's the version that works, which hopefully will shed some light on what I am trying to achieve:
#include <iostream>
#include <type_traits>
typedef int i32;
template<class T>
struct rtvec
{
private:
T* e;
i32 d;
public:
rtvec(i32 d) : d(d), e(new T[d]) {}
//template<typename Args...>
//rtvec()
rtvec(const rtvec& in) : d(in.d), e(new T[in.d])
{
for (i32 i = 0; i < d; ++i)
at(i) = in.at(i);
}
rtvec(rtvec<typename std::remove_pointer_t<T>>& in) : d(in.dim()), e(new T[in.dim()])
{
for (i32 i = 0; i < d; ++i)
e[i] = &in.at(i);
}
~rtvec() { delete[] e; }
i32 dim() const { return d; }
template<typename U=T,
typename std::enable_if_t<std::is_same_v<U,T>>* = nullptr,
typename std::enable_if_t<!std::is_pointer_v<U>>* = nullptr>
inline T& at(i32 i)
{
return e[i];
}
template<typename U = T,
typename std::enable_if_t<std::is_same_v<U, T>>* = nullptr,
typename std::enable_if_t<std::is_pointer_v<U>>* = nullptr>
inline typename std::remove_pointer_t<T>& at(i32 i)
{
return *e[i];
}
};
int main()
{
rtvec<float> v(2);
v.at(0) = 1;
v.at(1) = 2;
rtvec<float*> p = v;
p.at(0) = 5;
std::cout << v.at(0) << " " << v.at(1) << "\n";
return 0;
}
Basically I am trying to make a runtime variable dimensional vector class, which when instantiated with a pointer, can be used as a sort of reference to a vector of the same type (more precisely I have several arrays of each of the coordinates of a set of points and I want to use the "reference" vector to be able to work with those as if they were ordered the other way around in memory).
When I try to simplify the code, however, by trying to remove what I perceive as an unnecessary typename U. I get the following compilation error in MSVC2017: std::enable_if_t<false,void>' : Failed to specialize alias template. Here's the less verbose version that I was aiming at achieving:
struct rtvec
{
private:
T* e;
i32 d;
public:
rtvec(i32 d) : d(d), e(new T[d]) {}
template<typename std::enable_if_t<!std::is_pointer_v<T>>* = nullptr>
rtvec(const rtvec& in) : d(in.d), e(new T[in.d])
{
for (i32 i = 0; i < d; ++i)
at(i) = in.at(i);
}
template<typename std::enable_if_t<std::is_pointer_v<T>>* = nullptr>
rtvec(rtvec<typename std::remove_pointer_t<T>>& in) : d(in.dim()), e(new T[in.dim()])
{
for (i32 i = 0; i < d; ++i)
e[i] = &in.at(i);
}
~rtvec() { delete[] e; }
i32 dim() const { return d; }
template<typename std::enable_if_t<!std::is_pointer_v<T>>* = nullptr>
inline T& at(i32 i)
{
return e[i];
}
template<typename std::enable_if_t<std::is_pointer_v<T>>* = nullptr>
inline typename std::remove_pointer<T>::type& at(i32 i)
{
return *e[i];
}
};
If I modify this a little, however, it does compile:
template<class T>
struct rtvec
{
private:
T* e;
i32 d;
public:
rtvec(i32 d) : d(d), e(new T[d]) {}
template<typename std::enable_if_t<!std::is_pointer_v<T>>* = nullptr>
rtvec(const rtvec& in) : d(in.d), e(new T[in.d])
{
for (i32 i = 0; i < d; ++i)
at(i) = in.at(i);
}
/*template<typename std::enable_if_t<std::is_pointer_v<T>>* = nullptr>
rtvec(rtvec<typename std::remove_pointer_t<T>>& in) : d(in.dim()), e(new T[in.dim()])
{
for (i32 i = 0; i < d; ++i)
e[i] = &in.at(i);
}*/
~rtvec() { delete[] e; }
i32 dim() const { return d; }
template<typename std::enable_if_t<!std::is_pointer_v<T>>* = nullptr>
inline T& at(i32 i)
{
return e[i];
}
/*template<typename std::enable_if_t<std::is_pointer_v<T>>* = nullptr>
inline typename std::remove_pointer<T>::type& at(i32 i)
{
return *e[i];
}*/
};
(as long as the part relating to the pointer is commented out in main too). I want to understand what is it that makes the 2nd code not compile.
The reason I am not directly specializing the class is that in my original implementation I have a lot of other member functions that will be equivalent between the two specializations which I do not want to repeat.
When I try to simplify the code, however, by trying to remove what I perceive as an unnecessary
Unfortunately (if I understand correctly) you have removed something that is necessary
If I understand correctly, you have simplified the following methods
template<typename U=T,
typename std::enable_if_t<std::is_same_v<U,T>>* = nullptr,
typename std::enable_if_t<!std::is_pointer_v<U>>* = nullptr>
inline T& at(i32 i)
{
return e[i];
}
template<typename U = T,
typename std::enable_if_t<std::is_same_v<U, T>>* = nullptr,
typename std::enable_if_t<std::is_pointer_v<U>>* = nullptr>
inline typename std::remove_pointer_t<T>& at(i32 i)
{
return *e[i];
}
as follows
template<typename std::enable_if_t<!std::is_pointer_v<T>>* = nullptr>
inline T& at(i32 i)
{
return e[i];
}
template<typename std::enable_if_t<std::is_pointer_v<T>>* = nullptr>
inline typename std::remove_pointer<T>::type& at(i32 i)
{
return *e[i];
}
Unfortunately SFINAE, over a template method, works only when uses tests (std::enable_if_t) based on template parameters of the method itself.
I mean: SFINAE doesn't works when the std::enable_if_t tests involve T (and only T) because T is a template parameter of the struct, not a template parameter of the method.
So you need the trick
typename U = T
that "transform" the T type in a template parameter of the method.
You can simplify a little removing the typename before std::enable_if_t because the "_t" is exactly typename (see the definition of std::enable_if_t)
Off topic: I'm not a language layer but, as far I know,
std::enable_if_t<std::is_same_v<U,T>>* = nullptr
isn't perfectly legal; I suggest to rewrite using int instead of void *
std::enable_if_t<std::is_same_v<U,T>, int> = 0
or maybe bool
std::enable_if_t<std::is_same_v<U,T>, bool> = true
or other integer types
Concluding, I suggest to rewrite your at() method as follows
template <typename U = T,
std::enable_if_t<std::is_same_v<U, T>, int> = 0,
std::enable_if_t<!std::is_pointer_v<U>, int> = 0>
inline T& at(i32 i)
{
return e[i];
}
template<typename U = T,
std::enable_if_t<std::is_same_v<U, T>, int> = 0,
std::enable_if_t<std::is_pointer_v<U>, int> = 0>
inline typename std::remove_pointer_t<T>& at(i32 i)
{
return *e[i];
}
There are several reasons and you need to provide the full compilation error. Regarding your code, you seem to use C++17.
For instance, in this code you are trying to return a reference to the object stored in the array, right?:
inline typename std::remove_pointer<T>::type& at(i32 i) {
return *e[i];
}
Can be replaced with a more STL-Like code:
using reference = T&;
using const_reference = const T&;
reference at(i32 i) {
return e[i];
}
const_reference at(i32 i) const {
return e[i];
}
Or use auto:
auto at(i32 i) const {
return e[i];
}
This is the way most of the STL containers work. For instance, if you access an std::vector<T*>, it will return a reference to a T*, not a reference to the data where T points.
Regarding the SFINAE technique you are using, I am not sure if it's properly written.
For instance, take a look into this post to find information about the proper ways to write the conditions for selecting constructors. Small sumary:
template <typename = typename std::enable_if<... condition...>::type>
explicit MyAwesomeClass(MyAwesomeClass<otherN> const &);
For instance, if you want to enable a constructor only for those instance that do not hold a pointer type:
template<typename = typename std::enable_if_t<!std::is_pointer_v<T>>>
explicit rtvec(const rtvec& in) : d(in.d), e(new T[in.d]) {
for (i32 i = 0; i < d; ++i)
at(i) = in.at(i);
}
Now, regarding the fact that you are using C++17, you can us constexpr if that will make your life much easy and handle the different situations. Something like this, I guess:
template <typename U>
explicit rtvec(const rtvec<U>& in) : d(in.d), e(new T[in.d]) {
for (i32 i = 0; i < d; ++i){
if constexpr (std::is_pointer<T>::value &&
std::is_pointer<U>::value) {
// ...
} else if constexpr (!std::is_pointer<T>::value &&
std::is_pointer<U>::value) {
// ...
} else {
// rest of possible combinations
}
}
}
My Problem is the following. I want to sort a list of types based on a list of constexpr values. The problem can be boiled down to this function:
template <typename U, typename V>
auto min(U,V) -> std::conditional_t<U::value < V::value, U, V>
{ return {}; }
whereas value must be some static constexpr member of each type, respecively.
The following snippet demonstrates the usage:
// (I)
// This must even be declared outside of a function body due to the statics :(
struct X { static constexpr double value = 2.; };
struct Y { static constexpr double value = 1.; };
int main()
{
X x;
Y y;
auto z = min(x,y);
std::cout << typeid(z).name() << " : " << z.value << std::endl;
}
My goal is to provide the value as I call the function. The closest thing I got to this goal is
the following
template <double (*F)()>
struct Value { static constexpr double value = F(); };
which can be called like this using lambdas:
// (II)
auto w = min(Value<[]{ return 3.14; }>{}, Value<[]{ return 2.71; }>{});
std::cout << typeid(w).name() << " : " << w.value << std::endl;
The actual type to be sorted can be an additional parameter.
The problem is that the above is not valid C++ according to the standard. However, the latest clang does compile
this gracefully.
Now, my question is: Is there another standard compliant way to achieve the above (listing (II)), that is, defining a function that
computes a type based on constexor objects provided inplace (in some way) as the function argument?
P.S.: I'm aware of the solution using std::integral_constant. This, however, is limited to integral types only. I'm interested in a solution that works for all constexpr objects, in particular floating point types, and strings.
Edit:
To deal with floating point values as well as integral types scenarios you could make use of user defined literal template e.g.:
#include <type_traits>
#include <utility>
#include <typeinfo>
#include <iostream>
template <class FloatingPointType, class... Cs>
constexpr FloatingPointType char_list_to_(Cs... cs) {
char arr[] = {cs...};
FloatingPointType lhs = 0;
bool contains_dot = false;
for (std::size_t i = 0; i < sizeof...(Cs) && !(contains_dot |= (arr[i] == '.')); i++) {
lhs *= 10;
lhs += arr[i] - '0';
}
FloatingPointType rhs = 0;
for (int i = sizeof...(Cs) - 1; i > 0 && arr[i] != '.'; i--) {
rhs /= 10;
rhs += arr[i] - '0';
}
rhs /= 10;
return (contains_dot)?lhs+rhs:lhs;
}
template <class FloatingPointType, char... Cs>
struct FloatingPointValue {
static constexpr FloatingPointType value = char_list_to_<FloatingPointType>(Cs...);
constexpr operator FloatingPointType() {
return value;
}
};
template <class FloatingPointType, char... Cs>
constexpr FloatingPointType FloatingPointValue<FloatingPointType, Cs...>::value;
template <char... Cs>
FloatingPointValue<double, Cs...> operator""_fv() {
return {};
}
template <typename U, typename V>
auto min(U,V) -> std::conditional_t<(U{}<V{}), U, V>
{ return {}; }
int main() {
auto w = min(3.14_fv, 2.71_fv);
std::cout << typeid(w).name() << " : " << w.value << std::endl;
}
Output:
18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE : 2.71
Output of c++filt -t 18FloatingPointValueIdJLc50ELc46ELc55ELc49EEE:
FloatingPointValue<double, (char)50, (char)46, (char)55, (char)49>
[live demo]
But if you wish to apply the same to string literal there is currently a lack of support of the feature caused by a c++ standard. There is however a gnu extension supported by clang and gcc if you are capable to accept less portable option:
#include <type_traits>
#include <utility>
#include <typeinfo>
#include <iostream>
template <class CharT, CharT... Cs>
struct Value {
static constexpr std::size_t size = sizeof...(Cs);
static constexpr CharT const value[sizeof...(Cs) + 1] = {Cs..., '\0'};
template <class RHS>
constexpr bool operator<(RHS) {
for (std::size_t i = 0; i < size && i < RHS::size; i++) {
if (value[i] != RHS::value[i]) {
return value[i] < RHS::value[i];
}
}
return size < RHS::size;
}
};
template <class CharT, CharT... Cs>
constexpr CharT const Value<CharT, Cs...>::value[sizeof...(Cs) + 1];
template <class CharT, CharT... Cs>
Value<CharT, Cs...> operator""_v() {
return {};
}
template <typename U, typename V>
auto min(U,V) -> std::conditional_t<(U{}<V{}), U, V>
{ return {}; }
int main() {
auto w = min("cde"_v, "abc"_v);
std::cout << typeid(w).name() << " : " << w.value << std::endl;
}
Output:
5ValueIcJLc97ELc98ELc99EEE : abc
Output of c++filt -t 5ValueIcJLc97ELc98ELc99EEE:
Value<char, (char)97, (char)98, (char)99>
[live demo]
I would like to be able to do something like the following:
struct A {};
template<typename T, typename U> struct B : public A {};
std::unique_ptr<A> chooseB(int i, int j)
{
// return B<T, U> where T and U vary with i and j (0 = int, 1 = double etc.)
}
i and j are not known at compile time. Potentially the list of types could be long enough that just forming a big conditional that enumerates all possible pairs of i and j could be painful.
Is there are nice way to write the chooseB function? I might potentially want to generalize this to more than two template parameters.
Time for some abuse.
We're going to write a function that will figure out which type corresponds to a given index. But we can't return that type - the return type must be known at compile-time. So instead we'll forward that along to a function that we provide. I'll start with the end-result:
std::unique_ptr<A> chooseB(int i, int j)
{
using choices = typelist<int, double>;
return pick_elem<std::unique_ptr<A>>(i, choices{},
[=](auto tag1){
return pick_elem<std::unique_ptr<A>>(j, choices{},
[=](auto tag2) {
using T1 = typename decltype(tag1)::type;
using T2 = typename decltype(tag2)::type;
return std::make_unique<B<T1, T2>>();
});
});
}
pick_elem takes three arguments: the index, the list of choices, and the function to forward along with. So we call it with the first index and call a lambda -- which in turns calls it with the second index and calls another lambda -- which finally makes our B.
You have to explicitly provide the return type to pick_elem<> because it needs to halt recursion somehow and that end-step will need to know what to return. So we start with some convenient metaprogramming helpers:
template <class... > struct typelist {};
template <class T> struct tag { using type = T; };
And then pick_elem is:
template <class R, class F>
R pick_elem(int , typelist<>, F )
{
throw std::runtime_error("wtf");
}
template <class R, class T, class... Ts, class F>
R pick_elem(int i, typelist<T, Ts...>, F f)
{
if (i == 0) {
return f(tag<T>{});
}
else {
return pick_elem<R>(i-1, typelist<Ts...>{}, f);
}
}
This can be generalized to arbitrarily many types by making chooseB variadic itself. In a way, this is actually cleaner than what I had before. chooseB() now additionally takes some non-deducible arguments that are the types we've figured out so far:
template <class... Ts>
std::unique_ptr<A> chooseB()
{
return std::make_unique<B<Ts...>>();
}
template <class... Ts, class Idx, class... Rest>
std::unique_ptr<A> chooseB(Idx i, Rest... rest)
{
using choices = typelist<int, double>;
return pick_elem<std::unique_ptr<A>>(i, choices{},
[=](auto tag){
return chooseB<Ts..., typename decltype(tag)::type>(rest...);
});
}
You can add some safety around this by asserting that the number of arguments is correct.
My pragmatic solution inspired by 0x499602D2 above. This will actually probably work for OK for the problem at hand - but I was interested in more general answers that don't rely on specific enumeration of all possibilities.
struct A
{
virtual ~A() = default;
virtual void printTypes() = 0;
};
template<typename T, typename U>
struct B : public A
{
virtual void printTypes() override
{
std::cout << typeid(T).name() << ", " << typeid(U).name() << std::endl;
}
};
int main()
{
std::map<std::pair<int, int>, std::function<std::unique_ptr<A> ()>> m =
{
{{0, 0}, [](){return std::unique_ptr<A>(new B<int, int>);}},
{{0, 1}, [](){return std::unique_ptr<A>(new B<int, double>);}},
{{1, 0}, [](){return std::unique_ptr<A>(new B<double, int>);}},
{{1, 1}, [](){return std::unique_ptr<A>(new B<double, double>);}}
};
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 2; ++j)
{
auto a = m[std::make_pair(i, j)]();
a->printTypes();
}
}
}
You can map both numbers to instantiations of the base class:
#define FWD(x) std::forward<decltype(x)>((x))
auto p=[](auto&&l,auto&&r){return std::make_pair(FWD(l),FWD(r));};
std::unique_ptr<A> chooseB(int i, int j) {
std::map<std::pair<int,int>,std::unique_ptr<A>> m;
m.emplace(p(p(0,0),std::make_unique<B<int,int>>()));
m.emplace(p(p(0,1),std::make_unique<B<int,double>>()));
m.emplace(p(p(1,0),std::make_unique<B<double,int>>()));
m.emplace(p(p(1,1),std::make_unique<B<double,double>>()));
/* and so on for different (i,j) */
return std::move(m[p(i,j)]);
}
If you want to generalize this for more than two parameters, then have the function take a parameter pack (Args&&...) possibly SFINAE-ified to all integers, and use a std::tuple<std::decay_t<Args...>> instead of a pair.
Make a jump table and dispatch.
template<size_t I, class... Ts>
std::unique_ptr<A> do_make() {
using T = std::tuple_element_t<I / sizeof...(Ts), std::tuple<Ts...>>;
using U = std::tuple_element_t<I % sizeof...(Ts), std::tuple<Ts...>>;
return std::make_unique<B<T,U>>();
}
template<class... Ts, size_t...Is>
std::unique_ptr<A> make(size_t i, size_t j, std::index_sequence<Is...>) {
using fptr_t = std::unique_ptr<A> (*)();
static constexpr fptr_t table[] = { do_make<Is, Ts...> ...};
return table[ i * sizeof...(Ts) + j]();
}
template<class... Ts>
std::unique_ptr<A> make(size_t i, size_t j) {
return make<Ts...>(i, j, std::make_index_sequence<sizeof...(Ts) * sizeof...(Ts)>());
}
typedef std::tuple< int, double > Tuple;
Tuple t;
int a = std::get<0>(t);
double b = std::get<1>(t);
for( size_t i = 0; i < std::tuple_size<Tuple>::value; i++ ) {
std::tuple_element<i,Tuple>::type v = std::get<i>(t);// will not compile because i must be known at compile time
}
I know it is possible to write code for get std::get working (see for example iterate over tuple ), is it possible to get std::tuple_element working too?
Some constraints (they can be relaxed):
no variadic templates, no Boost
C++ is a compile-time typed language. You cannot have a type that the C++ compiler cannot determine at compile-time.
You can use polymorphism of various forms to work around that. But at the end of the day, every variable must have a well-defined type. So while you can use Boost.Fusion algorithms to iterate over variables in a tuple, you cannot have a loop where each execution of the loop may use a different type than the last.
The only reason Boost.Fusion can get away with it is because it doesn't use a loop. It uses template recursion to "iterate" over each element and call your user-provided function.
If you want to do without boost, the answers to iterate over tuple already tell you everything you need to know. You have to write a compile-time for_each loop (untested).
template<class Tuple, class Func, size_t i>
void foreach(Tuple& t, Func fn) {
// i is defined at compile-time, so you can write:
std::tuple_element<i, Tuple> te = std::get<i>(t);
fn(te);
foreach<i-1>(t, fn);
}
template<class Tuple, class Func>
void foreach<0>(Tuple& t, Func fn) { // template specialization
fn(std::get<0>(t)); // no further recursion
}
and use it like that:
struct SomeFunctionObject {
void operator()( int i ) const {}
void operator()( double f ) const {}
};
foreach<std::tuple_size<Tuple>::value>(t, SomeFunctionObject());
However, if you want to iterate over members of a tuple, Boost.Fusion really is the way to go.
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/adapted/boost_tuple.hpp>
and in your code write:
boost::for_each(t, SomeFunctionObject());
This an example for boost::tuple. There is an adapter for boost::fusion to work with the std::tuple here: http://groups.google.com/group/boost-list/browse_thread/thread/77622e41af1366af/
No, this is not possible the way you describe it. Basically, you'd have to write your code for every possible runtime-value of i and then use some dispatching-logic (e.g. switch(i)) to run the correct code based on the actual runtime-value of i.
In practice, it might be possible to generate the code for the different values of i with templates, but I am not really sure how to do this, and whether it would be practical. What you are describing sounds like a flawed design.
Here is my tuple foreach/transformation function:
#include <cstddef>
#include <tuple>
#include <type_traits>
template<size_t N>
struct tuple_foreach_impl {
template<typename T, typename C>
static inline auto call(T&& t, C&& c)
-> decltype(::std::tuple_cat(
tuple_foreach_impl<N-1>::call(
::std::forward<T>(t), ::std::forward<C>(c)
),
::std::make_tuple(c(::std::get<N-1>(::std::forward<T>(t))))
))
{
return ::std::tuple_cat(
tuple_foreach_impl<N-1>::call(
::std::forward<T>(t), ::std::forward<C>(c)
),
::std::make_tuple(c(::std::get<N-1>(::std::forward<T>(t))))
);
}
};
template<>
struct tuple_foreach_impl<0> {
template<typename T, typename C>
static inline ::std::tuple<> call(T&&, C&&) { return ::std::tuple<>(); }
};
template<typename T, typename C>
auto tuple_foreach(T&& t, C&& c)
-> decltype(tuple_foreach_impl<
::std::tuple_size<typename ::std::decay<T>::type
>::value>::call(std::forward<T>(t), ::std::forward<C>(c)))
{
return tuple_foreach_impl<
::std::tuple_size<typename ::std::decay<T>::type>::value
>::call(::std::forward<T>(t), ::std::forward<C>(c));
}
The example usage uses the following utility to allow printing tuples to ostreams:
#include <cstddef>
#include <ostream>
#include <tuple>
#include <type_traits>
template<size_t N>
struct tuple_print_impl {
template<typename S, typename T>
static inline void print(S& s, T&& t) {
tuple_print_impl<N-1>::print(s, ::std::forward<T>(t));
if (N > 1) { s << ',' << ' '; }
s << ::std::get<N-1>(::std::forward<T>(t));
}
};
template<>
struct tuple_print_impl<0> {
template<typename S, typename T>
static inline void print(S&, T&&) {}
};
template<typename S, typename T>
void tuple_print(S& s, T&& t) {
s << '(';
tuple_print_impl<
::std::tuple_size<typename ::std::decay<T>::type>::value
>::print(s, ::std::forward<T>(t));
s << ')';
}
template<typename C, typename... T>
::std::basic_ostream<C>& operator<<(
::std::basic_ostream<C>& s, ::std::tuple<T...> const& t
) {
tuple_print(s, t);
return s;
}
And finally, here is the example usage:
#include <iostream>
using namespace std;
struct inc {
template<typename T>
T operator()(T const& val) { return val+1; }
};
int main() {
// will print out "(7, 4.2, z)"
cout << tuple_foreach(make_tuple(6, 3.2, 'y'), inc()) << endl;
return 0;
}
Note that the callable object is constructed so that it can hold state if needed. For example, you could use the following to find the last object in the tuple that can be dynamic casted to T:
template<typename T>
struct find_by_type {
find() : result(nullptr) {}
T* result;
template<typename U>
bool operator()(U& val) {
auto tmp = dynamic_cast<T*>(&val);
auto ret = tmp != nullptr;
if (ret) { result = tmp; }
return ret;
}
};
Note that one shortcoming of this is that it requires that the callable returns a value. However, it wouldn't be that hard to rewrite it to detect whether the return type is void for a give input type, and then skip that element of the resulting tuple. Even easier, you could just remove the return value aggregation stuff altogether and simply use the foreach call as a tuple modifier.
Edit:
I just realized that the tuple writter could trivially be written using the foreach function (I have had the tuple printing code for much longer than the foreach code).
template<typename T>
struct tuple_print {
print(T& s) : _first(true), _s(&s) {}
template<typename U>
bool operator()(U const& val) {
if (_first) { _first = false; } else { (*_s) << ',' << ' '; }
(*_s) << val;
return false;
}
private:
bool _first;
T* _s;
};
template<typename C, typename... T>
::std::basic_ostream<C> & operator<<(
::std::basic_ostream<C>& s, ::std::tuple<T...> const& t
) {
s << '(';
tuple_foreach(t, tuple_print< ::std::basic_ostream<C>>(s));
s << ')';
return s;
}