I have methods with the following signature:
void DoStuff(int i);
void DoStuff(int i, k);
void DoStuff(int i, int k, int l);
I have a method from where I would like to call the DoStuff methods as follows:
void CallDoStuff(const std::vector<int>& vElements) {
// What magic is supposed to happen here to make vElements an expandable pack?
DoStuff(vElemets...);
}
Is there any chance to achieve this?
Is using std::index_sequence the right way? If yes, could you please provide me a simple example how to apply this to my problem?
The problem is that, from a std::vector, you can't -- compile time -- extract the size() value.
So you can obtain what you want only if you pass, as a compile-time known value, to CallDoStuff() the number of elements that you want to use from the vector.
You can pass it as, by example, a template value.
Using an helper function, you can write something as follows
template <std::size_t ... Is>
void CallDoStuff (std::vector<int> const & vElements,
std::index_sequence<Is...> const &)
{ DoStuff(vElements[Is]...); }
template <std::size_t N>
void CallDoStuff (std::vector<int> const & vElements)
{ CallDoStuff(vElements, std::make_index_sequence<N>{}); }
The call could be something as
CallDoStuff<5u>(v);
If you can use a std::array, instead of std::vector, the answer is different: you can extract the size() from the type itself, so
template <std::size_t N, std::size_t ... Is>
void CallDoStuff (std::array<int, N> const & vElements,
std::index_sequence<Is...> const &)
{ DoStuff(vElements[Is]...); }
template <std::size_t N>
void CallDoStuff (std::array<int, N> const & vElements)
{ CallDoStuff(vElements, std::make_index_sequence<N>{}); }
that is callable without explicating N as follows
std::array<int, 5u> arr { 2, 3, 5, 7, 11 };
CallDoStuff(arr); // no more <5u>
End note: observe that std::make_index_sequence and std::index_sequence are available only starting from C++14. In C++11 you have to substitute them in some way.
It's possible, as long as you provide an upper bound to the number of arguments.
Using Xeo's implementation of std::index_sequence for C++11:
template <unsigned... Idx>
void trampoline(const std::vector<int>& vElements, seq<Idx...>) {
return DoStuff(vElements[Idx]...);
}
template <std::size_t Arity>
void trampoline(const std::vector<int>& vElements) {
return trampoline(vElements, typename gen_seq<Arity>::seq{});
}
template <unsigned... Idx>
void CallDoStuff(const std::vector<int>& vElements, seq<Idx...>) {
using trampoline_t = void (*)(const std::vector<int>&);
constexpr trampoline_t trampolines[]{
trampoline<Idx>...
};
trampolines[vElements.size()](vElements);
}
template <std::size_t Max>
void CallDoStuff(const std::vector<int>& vElements) {
assert(vElements.size() <= Max);
return CallDoStuff(vElements, typename gen_seq<Max + 1>::seq{});
}
See it live on Wandbox
This can't be done, a template method call is bound at compile time but a std::vector doesn't know how many items it contains until runtime so there's no way to mix the two concepts.
DoStuff(vElemets...);
Here the compiler should choose the correct implementation according to how many elements vElements has. You see the flaw in this kind of thinking since std::vector is just an object that could contain any amount of items at point of invocation.
Related
I would like to know if it is possible to have a for loop in compile time with runtime or even compile time limit condition in c++11?
I start with a silly try to find out what I need.
for (uint32_t i = 0; i < n; ++i)
{
templated_func<i>();
}
consider I have a class with a private member variable n, and I want to call a template function with a different number that iterates from 0 to n (for the case of runtime limit condition)
I've had studies on the "Template Metaprogramming" and "Constexpr If" (c++17) but I have not gotten any results, can anyone help me?
You can't have a for loop, but you can call N lots of templated_func
namespace detail {
template <template<uint32_t> class F, uint32_t... Is>
void static_for_impl(std::integer_sequence<uint32_t, Is...>)
{
F<Is>{}()...;
}
}
template <template<uint32_t> class F, uint32_t N>
void static_for()
{
detail::static_for_impl<F>(std::make_integer_sequence<uint32_t, N>{});
}
template <uint32_t I>
struct templated_caller
{
void operator()() { templated_func<I>(); }
}
int main()
{
static_for<templated_caller, 10>();
return 0;
}
Note that this is more general than what you asked for. You can simplify it to just
template <uint32_t... Is>
void call_templated_func(std::integer_sequence<uint32_t, Is...>)
{
templated_func<Is>()...;
}
int main()
{
call_templated_func(std::make_integer_sequence<uint32_t, N>{});
return 0;
}
but that's lengthy to repeat multiple times, and you can't pass a function template as a template parameter.
As you said you only had C++11 then you will not have std::make_index_sequence and will have to provide it. Also, the fold expression in Caleth's answer is not available until C++17.
Providing your own implementation of index_sequence and a fold expression in c++11 can be done in the following way,
#include <iostream>
template <size_t... Is>
struct index_sequence{};
namespace detail {
template <size_t I,size_t...Is>
struct make_index_sequence_impl : make_index_sequence_impl<I-1,I-1,Is...> {};
template <size_t...Is>
struct make_index_sequence_impl<0,Is...>
{
using type = index_sequence<Is...>;
};
}
template<size_t N>
using make_index_sequence = typename detail::make_index_sequence_impl<N>::type;
template<size_t I>
void templated_func()
{
std::cout << "templated_func" << I << std::endl;
}
template <size_t... Is>
void call_templated_func(index_sequence< Is...>)
{
using do_ = int[];
do_ {0,(templated_func<Is>(),0)...,0};
}
int main()
{
call_templated_func(make_index_sequence< 10>());
return 0;
}
This is essentially the same as the answer by #Caleth , but with the missing bits provided and will compile on c++11.
demo
demo on c++11 compiler
I would like to know if it is possible to have a for loop in compile time with runtime or even compile time limit condition in c++11
I don't know a reasonable way to have such loop with a runtime condition.
With a compile time condition... If you can use at least C++14, you can use a solution based on std::integer_sequence/std::make_integer_sequence (see Caleth answer) or maybe std::index_sequence/std::make_index_sequence (just a little more synthetic).
If you're limited with C++11, you can create a surrogate for std::index_sequence/std::make_index_sequence or you can create a recursive template struct with static function (unfortunately you can partially specialize a template function but you can partially specialize classes and structs).
I mean... something as follows
template <std::size_t I, std::size_t Top>
struct for_loop
{
static void func ()
{
templated_func<I>();
for_loop<I+1u, Top>::func();
}
};
template <std::size_t I>
struct for_loop<I, I>
{ static void func () { } };
that you can call
constexpr auto n = 10u;
for_loop<0, n>::func();
if you want to call templated_func() with values from zero to n-1u.
Unfortunately this solution is recursive so you can have troubles with compilers recursion limits. That is... works only if n isn't high.
I am trying to store the parameter pack of lvalue references of a variadic template for later use.
I have the following working for now.
template <typename... Ts>
class Foo {
private:
std::tuple<Ts...> m_args;
public:
template<typename... Args>
Foo(Args&&... args) : m_args(std::make_tuple(std::forward<Args>(args)...))
{
}
};
int main() {
int x = 10;
int y = 20;
Foo<int, int> foo(x, y);
}
However, I would like to store the parameter pack as a reference so that I can access the same object later.
I am not sure how I can do that. Any help would be appreciated.
The best I can imagine, is the use of std::forward_as_tuple.
Unfortunately I don't see a way to use it with perfect forwarding: if you want register values in a tuple inside a class, you have to decide the type of the tuple one time for all.
The best I can imagine is a tuple of const references; something as follows
template <typename ... Ts>
class Foo
{
private:
std::tuple<Ts const & ...> m_args;
public:
Foo (Ts const & ... as) : m_args{std::forward_as_tuple(as...)}
{ }
};
I hope isn't necessary remember you how dangling references can be dangerous for a solution based on a tuple of references.
I need to do:
#include <utility>
double& f(int i); // gets reference to an element in an array to be modified
void g(double& a); // uses references to modify the arguments
void g(double& a, double& b);
// other functions g with different amount of double& parameters
template<int N> void callG()
{
// should call g with N parameters: g(f(0), f(1), , f(n));
}
int main()
{
callG<1>; // calls g(f(0));
callG<2>; // calls g(f(0), f(1));
return 0;
}
I tried
g(f(std::make_index_sequence<N>)...);
and some similar variants, but get
expected '(' for function-style cast or type construction
How do I make a parameter pack from an integer_sequence? Is there another solution?
You can only use the ... pack expansion operator when you have a pack. std::make_index_sequence<N> is not a pack. Add a layer of indirection:
template <std::size_t... Is>
void callGImpl(std::index_sequence<Is...>)
{
g(f(Is)...);
}
template<int N>
void callG()
{
callGImpl(std::make_index_sequence<N>{});
}
live example on wandbox.org
#include <utility>
double& f(int i);
void g(double& a);
void g(double& a, double& b);
template <size_t... Ints>
void callG(std::integer_sequence<size_t, Ints...>) {
g(f(Ints)...);
}
template <int N>
void callG() {
callG(std::make_index_sequence<N>());
}
int main() {
callG<1>();
callG<2>();
return 0;
}
I'm working on my own Lua engine with C++ 11, I want to write a function wrapper that register C++ function to Lua environment with variadic parameter. That's simple in C++ 0x, but boring cause I need to write similar codes to support function with 0~N parameters.
function push is used to push T to lua stack, where function upvalue_ get C++ function pointer with lua cclosure, and it assume the funtion is has two parameters T1 and T2, T1 is acquired from lua stack with index 1, and T2 is acquired from lua stack with index 2.
template <typename RVal, typename T1, typename T2>
struct functor<RVal,T1,T2>
{
static int invoke(lua_State *L)
{
push(L,upvalue_<RVal(*)(T1,T2)>(L)(read<T1>(L,1),read<T2>(L,2)));
return 1;
}
};
template<typename T>
T upvalue_(lua_State *L)
{
return user2type<T>::invoke(L, lua_upvalueindex(1));
}
and with C++ 11, I wrote such code snippets:
template< typename RVal, typename ... ARGS>
struct functor
{
static int invoke(lua_State* L)
{
typedef RVal (*FUNC_PTR)(ARGS...);
FUNC_PTR f = upvalue_<FUNC_PTR>(L);
push(L, f(read_stack<ARGS>(L)...));
return 1;
}
};
template<typename T>
T read_stack(lua_State* L)
{
T t = read<T>(L, -1);
lua_pop(L, 1);
return t;
}
the code shown above could work, but the parameter order is reversed because read_stack read parameter from the last index -1 always.
my question is how to read parameter from lua stack from 1 to N(N equals to sizeof...(ARGS) if ARGS not empty) with variadic template argument and pass them to real function pointer f to make real call?
Not specific to Lua, here is a general-purpose C++11 solution to reversing the order of given parameters to a function. In the below code, 'apply' is my example target function (here it just outputs a bit of text based on its variadic parameters). The 'main' functions shows how the helper function 'reverse_and_apply' takes a function (or Functor to be precise) and a set of arguments, and applies the given function to the reversed argument list using some template trickery. Note I apologise for the somewhat anal use of perfect forwarding here, which is technically correct but unfortunately obfuscates the code somewhat. Hopefully you get the main message.
#include <iostream>
template <typename ...Args>
void apply(const char* fmtString, const Args&... args)
{
char output[512];
snprintf(output, 512, fmtString, args...);
std::cout << output << std::endl;
}
template <typename F, typename ...Args>
struct ReverseAndApply;
template <typename F>
struct ReverseAndApply<F>
{
template <typename ... AlreadyReversed>
static void doIt(F func, AlreadyReversed&& ... args)
{
func(args...);
}
};
template <typename F, typename FirstArg, typename ...RestArgs>
struct ReverseAndApply<F, FirstArg, RestArgs...>
{
template <typename ... AlreadyReversed>
static void doIt(F func, FirstArg&& arg, RestArgs&& ... restArgs, AlreadyReversed&& ... revArgs)
{
ReverseAndApply<F, RestArgs...>::doIt(func, std::forward<RestArgs>(restArgs)..., std::forward<FirstArg>(arg), std::forward<AlreadyReversed>(revArgs)...);
}
};
template <typename F, typename... Args>
void reverse_and_apply(F func, Args&&... args)
{
ReverseAndApply<F, Args...>::doIt(func, std::forward<Args>(args)...);
}
int main()
{
reverse_and_apply(apply<double, const char*, int>, 1, (const char*)"abc", 2.0, "%f %s %d");
return 0;
}
Your code in C++11 not even work as the evaluation order of arguments is not defined.
It should be easy by using std::integer_sequence in C++14.
Sample code:
template< typename RVal, typename... ARGS>
struct functor
{
template <std::size_t... Is>
static int invoke_impl(lua_State *L, std::index_sequence<Is...>)
{
typedef RVal (*FUNC_PTR)(ARGS...);
FUNC_PTR f = upvalue_<FUNC_PTR>(L);
push(L, f(read<ARGS>(L, Is)...));
return 1;
}
static int invoke(lua_State* L)
{
return invoke_impl(L, std::index_sequence_for<ARGS...>{});
}
};
I am writing a library that uses variadic-templated functions, like so:
template<typename ... T>
void func(T ... args) {
// ...
}
I need to ensure code is generated for this function (i.e. explicit instantiation) for certain types, like so:
template class func<int>;
template class func<int, int>;
template class func<int, int, int>;
// ...
where the max number of int arguments is a non-const maxArgs() (I am unable to change this as it is an external function). I have tried the following:
template<typename ... T>
void f(size_t max, T ... args) { // Generates "infinitely"
if (sizeof...(T) < max) {
func(args...);
f(max, args..., 0);
}
}
int main(int argc, char** argv) {
f(maxArgs(), 0);
// ...
return 0;
}
However the compiler doesn't have a proper base-case to the function generation recursion, so it fails to compile. I've also tried using non-type templates like so (using some code from here):
template<int ...> struct seq { };
template<int N, int ... Ns> struct gens : gens<N-1, N-1, Ns...> { };
template<int ... Ns> struct gens<0, Ns...> { typedef seq<Ns...> type; };
std::vector<int> params;
template<int ... Ns>
void f(seq<Ns...>) {
test(std::get<Ns>(params)...);
}
void instantiate(size_t max) {
for (int i = 1; i < max; ++i) {
for (int j = 0; j < i; ++j) {
params.push_back(0);
}
f(typename gens<i>::type()); // Fails to compile -- i is not const
params.clear();
}
}
int main(int argc, char** argv) {
instantiate(maxArgs());
}
but this requires a const value, so it fails to compile as well. Is there any way to do this properly having no knowledge of the return value of maxArgs()?
No, you cannot possibly generate at compile time templates which depend on a value only known at runtime. You will need to choose some maximum value which is a constant ahead of time (and sometimes not use all the instantiations), or figure out a way to make maxArgs() a compile-time constant. Or compile your code on the fly when it's used!
Since you have more information than we do about this code, perhaps you can think about whether making it be a variadic template is actually required. It seems likely that it isn't, given that the number of template arguments is determined at runtime. It might be better to write a solution which is fully runtime determined, without the variadic template stuff.
Since I know there is a maximum possible value to maxArgs() (namely 42), I came up with the following solution thanks to the suggestion of #JohnZwinck.
#include <vector>
typedef void (*void_fnptr)();
std::vector<void_fnptr> table;
// Function that needs to be code-generated for certain number of int types
template<typename ... T>
void func(T ... args) {
// ...
}
template<typename T>
void instantiate(T elem) {
table.push_back((void_fnptr)func<T>);
}
template<typename T, typename ... Ts>
void instantiate(T first, Ts ... rest) {
table.push_back((void_fnptr)func<T, Ts...>);
instantiate(rest...);
}
int main(int argc, char** argv) {
// 42 int arguments:
instantiate(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
// ...
return 0;
}