I want to implement a compile-time foreach() which can call a given template member function N times.
Currently I have my compile-time foreach:
struct ForEach
{
template <size_t Dummy>
struct IntToType {};
typedef IntToType<true> ForEachDoNotTerminateLoop;
typedef IntToType<false> ForEachTerminateLoop;
template <size_t TIdx, size_t TCount, typename TMethod>
static void ForEachImpl(ForEachDoNotTerminateLoop, TMethod method)
{
method.Invoke<TIdx>();
ForEachImpl<TIdx + 1, TCount, TMethod>(Internal::IntToType<(TIdx + 1 < TCount)>(), method);
}
template <size_t TIdx, size_t TCount, typename TMethod>
static void ForEachImpl(ForEachTerminateLoop, TMethod method)
{
}
template <size_t TCount, typename TMethod>
static void Member(TMethod method)
{
ForEachImpl<0, TCount, TMethod>(Internal::IntToType<(0 < TCount)>(), method);
}
};
And some template class:
template <typename T, size_t TCount>
class SomeClass
{
public:
void Foo(int arg1)
{
ForEach::Member<TCount>(BarInvoker(this, arg1));
}
private:
struct BarInvoker // <-- How can I make this invoker a template to make it more flexible?
{
BarInvoker(SomeClass* instance, int arg1)
: instance(instance)
, arg1(arg1)
{}
template <size_t N>
void Invoke()
{
instance->Bar<N>(arg1);
}
int arg1;
SomeClass* instance;
};
template <size_t N>
void Bar(int arg1)
{
_data[N] = arg1;
}
int* _data;
T* _otherData;
};
Is there a way to bypass the "invoker" functor, to make it more flexible (template) and easier to use?
I don't really like to bloat my code by adding an "invoker" stub for each of my private member functions.
It would be nice to just call ForEach::Member<TCount, int>(Bar, 5);
Thanks in advance for helping me out with this template weirdness! :)
Wrapping the template function in a class and passing an instance of the class to ForEach::Call<> with arbitrary arguments to call it with, seem to be a fairly clean solution.
The ForEach::Call<>'s call looks like: ForEach::Call<N>(function_object, arguments...)
The function_object is a class that has an operator() defined as:
template <std::size_t Idx> // Current index in the for-loop.
void operator()(/* arguments... */) { /* Impl. */ }
Here is my version of the ForEach<>.
class ForEach {
public:
/* Call function f with arguments args N times, passing the current index
through the template argument. */
template <std::size_t N, typename F, typename... Args>
static void Call(F &&f, Args &&...args) {
Impl<0, N>()(std::forward<F>(f), std::forward<Args>(args)...);
}
private:
/* Forward declaration. */
template <std::size_t Idx, std::size_t End>
class Impl;
/* Base case. We've incremeneted up to the end. */
template <std::size_t End>
class Impl<End, End> {
public:
template <typename F, typename... Args>
void operator()(F &&, Args &&...) { /* Do nothing. */ }
}; // Impl<End, End>
/* Recursive case. Invoke the function with the arguments, while explicitly
specifying the current index through the template argument. */
template <std::size_t Idx, std::size_t End>
class Impl {
public:
template <typename F, typename... Args>
void operator()(F &&f, Args &&...args) {
std::forward<F>(f).template operator()<Idx>(std::forward<Args>(args)...);
Impl<Idx + 1, End>()(std::forward<F>(f), std::forward<Args>(args)...);
}
}; // Impl<Idx, End>
}; // ForEach
I've written something similar to your SomeClass to demonstrate its use.
template <std::size_t Size>
class Ints {
public:
using Data = std::array<int, Size>;
/* Call Assign, Size times, with data_ and n as the arguments. */
void AssignAll(int n) { ForEach::Call<Size>(Assign(), data_, n); }
/* Call Print, Size times, with data_ and n as the arguments. */
void PrintAll() const { ForEach::Call<Size>(Print(), data_); }
private:
/* Wraps our templated assign function so that we can pass them around. */
class Assign {
public:
template <size_t N>
void operator()(Data &data, int arg) const {
data[N] = arg;
}
}; // Assign
/* Wraps our templated print function so that we can pass them around. */
class Print {
public:
template <size_t N>
void operator()(const Data &data) const {
std::cout << data[N] << std::endl;
}
}; // Print
/* Our data. */
Data data_;
}; // Ints<Size>
Simple use case for the Ints class.
int main() {
Ints<5> ints;
ints.AssignAll(101);
ints.PrintAll();
}
Prints:
101
101
101
101
101
Related
Is there any way to call a class member function that takes only 1 template argument instead of 2?
I would like to write some code like this:
template<typename T, size_t N>
void Container<int, N>::quick_sort() {
}
You cannot partial specialize a method, you could partial specialize the whole class, but require some duplication.
template<typename T, size_t N>
class Container
{
// Some code ...
void quick_sort();
};
template <typename T,size_t N>
void Container<T, N>::quick_sort()
{
// ...
}
// Class specialization
template <size_t N>
class Container<int, N>
{
// Some similar/same code...
void quick_sort();
};
template <size_t N>
void Container<int, N>::quick_sort()
{
// ...
}
As alternative, C++17 allows
template<typename T, size_t N>
class Container
{
// Some code ...
void quick_sort()
{
if constexpr (std::is_same_v<int, T>) {
// ...
} else {
// ...
}
}
};
For prior versions, regular if would probably produces error (both branches should be valid, even if not taken).
So tag dispatching is an easy approach (SFINAE is another one):
template <typename> struct Tag{};
template<typename T, size_t N>
class Container
{
private:
void quick_sort(tag<int>)
{
// ...
}
template <typename U>
void quick_sort(tag<U>)
{
// ...
}
public:
void quick_sort()
{
quick_sort(Tag<T>());
}
// Some code ...
};
I am trying to find way to design a class template so that an int value is passed, and several function signatures as well as argument lists are dependent on this value.
Particularly, considering MyClass:
template <int N>
class MyClass {
typedef SomeType<int, int, int, /* ... N times*/ > MyDepType;
myFunction(std::string arg0, std::string arg1, /* ...*/ std::string argN) { /* do stuff */};
public:
MyClass() {
someFunction(float arg0, float arg1, /* ...*/ float argN); // <
someOtherFunction(boost::bind(&MyClass::myFunction, this, _1, _2, /*...*/ _N));
};
};
I'd like to be able to express both the private typedef call, the signature of myFunction and the argument list passed to external functions someFunction and someOtherFunction, which I can't edit/rewrite.
Is there a way to achieve this, using the C++11 standard?
You could use a trick like in this post (Produce std::tuple of same type in compile time given its length by a template argument) to produce a tuple of N elements.
template <int N, typename T>
struct tuple_n_impl {
template <typename... Ts>
using type = typename tuple_n_impl<N - 1, T>::template type<T, Ts...>;
};
template <typename T>
struct tuple_n_impl<0, T> {
template <typename... Ts>
using type = std::tuple<Ts...>;
};
template <int N, typename T>
using tuple_n = typename tuple_n_impl<N, T>::template type<>;
template <int N>
class MyClass {
void int_function(tuple_n<N, int>&& ints);
void float_function(tuple_n<N, float>&& floats);
template <typename T>
void any_function(tuple_n<N, T>&& elements);
};
You might use std::index_sequence (C++14, but implementation in C++11 can be found on SO):
template <std::size_t, typename T>
using always_t = T;
template <std::size_t ... Is>
class MyClassImpl {
using MyDepType = SomeType<always_t<Is, int>...>;
void myFunction(always_t<Is, std::string>... args) { /* do stuff */}
public:
MyClass() {
void someFunction(always_t<Is, std::float>... args);
someOtherFunction([this](always_t<Is, const std::string&>... args) {
return myFunction(args...);
});
//
std::array<std::string, sizeof...(Is)> strings = {std::to_string(Is)...};
myFunction(strings[Is]...);
};
};
template <std::size_t N>
using MyClass = MyClassImpl<std::make_index_sequence<N>>;
I am trying to write a class to represent a tensor Tensor and would like to provide the syntax tensor(i, j) for a 2 dimensional tensor, tensor (i, j, k) for a 3 dimensional tensor and so on.
What I want to know is if there is a c++ type safe way to declare such Tensor:operator()(int, int, ...) that accepts any number of int arguments (besides the C style with the macros va_start va_end) and how to use said arguments inside the function.
Thanks for your time.
Well, you could always use an ordinary parameter pack; but force a compilation failure unless all parameters are ints:
#include <utility>
#include <type_traits>
class foo {
public:
template<typename ...Args,
typename=std::void_t<std::enable_if_t
<std::is_same_v<Args, int>>...>>
void operator()(Args ...args)
{
}
};
void bar()
{
foo bar;
bar(4, 2);
}
That will compile, but not this:
bar(4, "foo");
or
bar(4, 2.3);
Note that this will not compile either:
unsigned baz=2;
bar(4, baz);
If you need to accept unsigned values, tweat the template accordingly.
Note that the template does not need to use a forwarding reference, since the only acceptable parameters are plain ints. Within the template function, you now have a garden-variety parameter pack, that you would use the same way you'd use any other parameter pack.
To accept also unsigned int and other types that are convertible to int, and if you can accept an upper limit (63, in the following example) to the number of integer argument, I propose to follow an example from W.F..
So you can develop a typer
template <typename T, std::size_t>
using typer = T;
and a recursive struct proOp
template <typename T, std::size_t N = 64U,
typename = std::make_index_sequence<N>>
struct proOp;
template <typename T, std::size_t N, std::size_t... Is>
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U>
{
using proOp<T, N-1U>::operator();
void operator() (typer<T, Is>... ts)
{ }
};
template <typename T>
struct proOp<T, 0U, std::index_sequence<>>
{
void operator() ()
{ }
};
Inheriting from proOp<int>, Tensor become
struct Tensor : public proOp<int>
{
using proOp<int>::operator();
};
The following is a full working example
#include <utility>
template <typename T, std::size_t>
using typer = T;
template <typename T, std::size_t N = 64U,
typename = std::make_index_sequence<N>>
struct proOp;
template <typename T, std::size_t N, std::size_t... Is>
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U>
{
using proOp<T, N-1U>::operator();
void operator() (typer<T, Is>... ts)
{ }
};
template <typename T>
struct proOp<T, 0U, std::index_sequence<>>
{
void operator() ()
{ }
};
struct Tensor : public proOp<int>
{
using proOp<int>::operator();
};
int main()
{
Tensor t;
t(1, 2, 3);
t(1, 2, 3, 4U); // accept also unsigned
//t(1, "two"); // error
}
Another way could be make operator() recursive and use the first argument in every recursion
// recursive case
template <typename ... Ts>
void operator() (int i0, Ts ... is)
{
// do something with i0
this->operator()(is...); // recursion
}
void operator() ()
{ }
The following is a full working example
struct Tensor
{
// recursive case
template <typename ... Ts>
void operator() (int i0, Ts ... is)
{
// do something with i0
this->operator()(is...); // recursion
}
void operator() ()
{ }
};
int main()
{
Tensor t;
t(1, 2, 3);
t(1, 2, 3, 4U); // accept also unsigned
//t(1, "two"); // error
}
There is a more laconic way for creating safe variadic function, without using recursion and std::enable_if:
template <typename ...Ints>
void function(int first, Ints... other)
{
int values[] = {first, other...};
for(int value : values)
{
//your code
}
}
This way is also type safe and function(1, "2", 3) won't compile.
Suppose I have the following function, that takes a function as a parameter.
template <typename F>
void test_func(F f)
{
// typedef typename function_traits<F>::return_type T;
typedef int T;
std::mt19937 rng(std::time(0));
std::uniform_int_distribution<T> uint_dist10(0, std::numeric_limits<T>::max());
f(uint_dist10(rng), uint_dist10(rng)); // Problem!
}
Usage would be:
int foo(int, int) { return 0; }
int bar(int, int, int, int) { return 0; }
int main()
{
test_func(foo);
// test_func(bar);
}
Just like foo and bar, I have several functions that return T, and take some amount of parameters of type T. I would like test_func to generate as many calls to my RNG as the function f takes parameters. In other words, we can assume T is always an integer type, and that each parameter will be the same, i.e. a function call to an RNG.
Using function_traits (such as the ones in Boost), I can fetch the return type of F, and that helps a little. Roughly, my question is
How can I generate a needed amount of function calls so that it matches the arity of the function F?
Before C++11, I would have looked at Boost.Preprocessor, or maybe relied on template specialization. Is there a nicer way of doing it now?
First define a meta function called arity to compute arity of the function (it is just a simple implementation; can be improved to compute arity of functors also. See my answer here.):
template<typename F>
struct arity;
template<typename R, typename ...Args>
struct arity<R (*)(Args...)>
{
static const std::size_t value = sizeof ... (Args);
};
then define another meta function called genseq to generate a compile time sequence of integral values:
template<int ... N>
struct seq
{
using type = seq<N...>;
template<int I>
struct push_back : seq<N..., I> {};
};
template<int N>
struct genseq : genseq<N-1>::type::template push_back<N-1> {};
template<>
struct genseq<0> : seq<> {};
template<int N>
using genseq_t = typename genseq<N>::type; //Just a friendly alias!
then a function invoker as:
template<typename F, typename ArgEvaluator, int ...N>
void invoke(seq<N...>, F f, ArgEvaluator arg_evaluator)
{
using arg_type = decltype(arg_evaluator());
constexpr std::size_t arity = sizeof ... (N);
arg_type args[] { (N, arg_evaluator()) ... }; //enforce order of evaluation
f( args[N] ... );
}
And then your code would become this:
template <typename F>
void test_func(F f)
{
// typedef typename function_traits<F>::return_type T;
typedef int T;
std::mt19937 rng(std::time(0));
std::uniform_int_distribution<T> uint_dist10(0, std::numeric_limits<T>::max());
//f(uint_dist10(rng), uint_dist10(rng)); // Problem!
auto arg_evaluator = [&]() mutable { return uint_dist10(rng); };
invoke(genseq_t<arity<F>::value>(), f, arg_evaluator);
}
Here is a sample demo.
Hope that helps.
No need for complicated meta calculations.
template <typename Ret, typename ... T>
void test_func (Ret f (T...))
{
std::mt19937 rng(std::time(0));
f((std::uniform_int_distribution<T>(0, std::numeric_limits<T>::max())(rng))...);
}
int moo(int, int, int){ return 0; }
int main ()
{
test_func(moo);
}
To support functors one needs a bit longer implementation, still not too complicated:
// separate arguments type from function/functor type
template <typename F, typename ... T>
void test_func_impl (F f)
{
std::mt19937 rng(std::time(0));
f((std::uniform_int_distribution<T>(0, std::numeric_limits<T>::max())(rng))...);
}
// overload for a straight function
template <typename Ret, typename ... T>
void test_func (Ret f (T...))
{
test_func_impl<decltype(f), T...>(f);
}
// forwarder for a functor with a normal operator()
template <typename F, typename Ret, typename... T>
void test_func_for_functor (F f, Ret (F::*)(T...))
{
test_func_impl<F, T...>(f);
}
// forwarder for a functor with a const operator()
template <typename F, typename Ret, typename... T>
void test_func_for_functor (F f, Ret (F::*)(T...)const)
{
test_func_impl<F, T...>(f);
}
// overload for anything that has operator()
template <typename F>
void test_func (F f)
{
test_func_for_functor(f, &F::operator());
}
I have the following code :
template<size_t sz,typename T=float> class Vec{
T v[sz];
Vec(const T& val,const T&... nv){
//how do i assign `sz` number of first arguments into `this->v` array
}
}
I want to create constructor, that receive generic number of constructor argument, and assign the first sz number of arguments into member variable of v
what I want to do, is to be able doing like this: Vec<3> var(1.0,2.0,3.0);
This is possible, but complicated. Here is some code that does it. It may be possible to eliminate the holder type, but I leave that as an exercise for the reader. This has been tested with g++ 4.6.
#include <iostream>
#include <typeinfo>
template<size_t ... Indices> struct indices_holder
{};
template<size_t index_to_add,typename Indices=indices_holder<> >
struct make_indices_impl;
template<size_t index_to_add,size_t...existing_indices>
struct make_indices_impl<index_to_add,indices_holder<existing_indices...> >
{
typedef typename make_indices_impl<
index_to_add-1,
indices_holder<index_to_add-1,existing_indices...> >::type type;
};
template<size_t... existing_indices>
struct make_indices_impl<0,indices_holder<existing_indices...> >
{
typedef indices_holder<existing_indices...> type;
};
template<size_t max_index>
typename make_indices_impl<max_index>::type make_indices()
{
return typename make_indices_impl<max_index>::type();
}
template<unsigned index,typename ... U>
struct select_nth_type;
template<unsigned index,typename T,typename ... U>
struct select_nth_type<index,T,U...>
{
typedef typename select_nth_type<index-1,U...>::type type;
static type&& forward(T&&,U&&... u)
{
return select_nth_type<index-1,U...>::forward(static_cast<U&&>(u)...);
}
};
template<typename T,typename ... U>
struct select_nth_type<0,T,U...>
{
typedef T type;
static type&& forward(T&&t,U&&...)
{
return static_cast<T&&>(t);
}
};
template<unsigned index,typename ... U>
typename select_nth_type<index,U...>::type&& forward_nth(U&&... u)
{
return static_cast<typename select_nth_type<index,U...>::type&&>(
select_nth_type<index,U...>::forward(
static_cast<U&&>(u)...));
}
template<size_t sz,typename T=float> struct Vec{
struct holder
{
T data[sz];
};
holder v;
template<typename ... U>
struct assign_helper
{
template<size_t... Indices>
static holder create_array(indices_holder<Indices...>,Vec* self,U&&... u)
{
holder res={{static_cast<T>(forward_nth<Indices>(u...))...}};
return res;
}
};
template<typename ... U>
Vec(U&&... u):
v(assign_helper<U...>::create_array(make_indices<sz>(),this,static_cast<U&&>(u)...))
{}
};
int main()
{
Vec<3> v(1.2,2.3,3.4,4.5,5.6,7.8);
std::cout<<"v[0]="<<v.v.data[0]<<std::endl;
std::cout<<"v[1]="<<v.v.data[1]<<std::endl;
std::cout<<"v[2]="<<v.v.data[2]<<std::endl;
}
I believe this satisfies all the requirements:
template <size_t sz,typename T,typename... Args> struct Assign;
template <typename T,typename First,typename...Rest>
struct Assign<1,T,First,Rest...> {
static void assign(T *v,const First &first,const Rest&... args)
{
*v = first;
}
};
template <size_t sz,typename T,typename First,typename... Rest>
struct Assign<sz,T,First,Rest...> {
static void assign(T *v,const First &first,const Rest&... rest)
{
*v = first;
Assign<sz-1,T,Rest...>::assign(v+1,rest...);
}
};
template<size_t sz,typename T=float>
struct Vec{
T v[sz];
template <typename... Args>
Vec(const T& val,const Args&... nv){
Assign<sz,T,T,Args...>::assign(v,val,nv...);
}
};
This is another technique which is much simpler if it is ok not to have at least sz parameters:
template<size_t sz,typename T=float>
struct Vec {
T v[sz];
template <typename... Args>
Vec(const T& val,const Args&... nv)
{
T data[] = {val,static_cast<const T &>(nv)...};
int i=0;
for (; i<sz && i<(sizeof data)/sizeof(T); ++i) {
v[i] = data[i];
}
for (; i<sz; ++i) {
v[i] = T();
}
}
};
First declare this utility function:
template <typename T> inline void push(T* p) {}
template <typename T, typename First, typename... Args>
inline void push(T* p, First&& first, Args&&... args)
{
*p = first;
push(++p, std::forward<Args>(args)...);
}
Then, in your class:
template<size_t sz,typename T=float>
class Vec
{
T v[sz];
template <typename... Args>
Vec(T first, Args&&... args) // << we have changed const T& to T&&
{
//how do i assign `sz` number of first arguments into `this->v` array
// like this:
push(&v[0], first, std::forward<Args>(args)...);
}
}
sz is a template argument, you can directly use it in your code.
The following could work:
template <typename T, std::size_t N>
struct Foo
{
T arr[N];
template <typename ...Args> Foo(Args &&... args) : arr{std::forward<Args>(args)...} { }
};
Usage:
Foo<int, 3> a(1,2,3);
This allows you to construct the array elements from anything that's convertible to T. You can obtain the number of parameters (which can be anything not exceeding N) with sizeof...(Args).
Can you make use of something like this?
template <typename... Args> class Vec {
std :: tuple <Args...> m_args;
Vec (const Foo & a, const Bar & b, Args&&... args)
: m_args (args...)
{
// ... something with a, b
}
};
There are a few rules to constrain you:
you can only have one template... Args-style packed argument list per template class
methods which use it must have the templated arguments on the right-hand-side
You need to unpack the argument pack while keeping a count and do the necessary runtime operation in a functor. This should get you started:
template<unsigned, typename...>
struct unroll;
template<unsigned size, typename Head, typename... Tail>
struct unroll<size, Head, Tail...> {
void operator()(Head&& h, Tail&&... tail) {
// do your stuff, pass necessary arguments through the ctor of the
// struct
unroll<size - 1, Tail...>()(std::forward<Tail>(tail)...);
}
};
template<typename Head, typename... Tail>
struct unroll<1, Head, Tail...> {
void operator()(Head&& h, Tail&&... tail) {
// do your stuff the last time and do not recurse further
}
};
int main()
{
unroll<3, int, double, int>()(1, 3.0, 2);
return 0;
}
The following almost works (and for the last N arguments instead of the first, but hey). Perhaps someone can help with the compile error in the comments below:
#include <iostream>
void foo (int a, int b) {
std :: cout << "3 args: " << a << " " << b << "\n";
}
void foo (int a, int b, int c) {
std :: cout << "3 args: " << a << " " << b << " " << c << "\n";
}
template <int n, typename... Args>
struct CallFooWithout;
template <typename... Args>
struct CallFooWithout <0, Args...> {
static void call (Args... args)
{
foo (args...);
}
};
template <int N, typename T, typename... Args>
struct CallFooWithout <N, T, Args...> {
static void call (T, Args... args)
{
CallFooWithout <N-1, Args...> :: call (args...);
// ambiguous class template instantiation for 'struct CallFooWithout<0, int, int, int>'
// candidates are: struct CallFooWithout<0, Args ...>
// struct CallFooWithout<N, T, Args ...>
}
};
template <int n, typename... Args>
void call_foo_with_last (Args... args)
{
CallFooWithout <sizeof...(Args)-n, Args...> :: call (args...);
}
int main ()
{
call_foo_with_last <2> (101, 102, 103, 104, 105);
call_foo_with_last <3> (101, 102, 103, 104, 105);
}
I don't see why it's ambiguous because 0 is more specialised than N so that should satisfy the partial order ?!?!?
By contrast, the below is fine.
template <int N, typename... T>
struct Factorial
{
enum { value = N * Factorial<N - 1,T...>::value };
};
template <typename... T>
struct Factorial<0, T...>
{
enum { value = 1 };
};
void foo()
{
int x = Factorial<4,int>::value;
}
What's the difference?