Passing position of variadic template argument - c++

I would like to create a function that takes a variable number of template arguments. Later with these arguments the function should pass their position like this:
template<typename R, typename Args...>
R myFunction(Data &data, void *function) {
auto f = (R (*)(Args...))function;
return f(read<Args1>(data, 1), read<Args2>(data, 2), ...);// <-- This is the problem
}
The given code is of course not compilable. Is there any way to fix it? Is there a way to do it without variadic templates without too much code duplication?

Yes, that is possible:
// we need a compile-time helper to generate indices
template< std::size_t... Ns >
struct indices
{
typedef indices< Ns..., sizeof...( Ns ) > next;
};
template< std::size_t N >
struct make_indices
{
typedef typename make_indices< N - 1 >::type::next type;
};
template<>
struct make_indices< 0 >
{
typedef indices<> type;
};
With these helpers, you need one forwarder for your function like this:
template<typename R, typename... Args, std::size_t... Ns>
R myFunctionImpl(void *Data, void *function, indices<Ns...> ) {
auto f = (R (*)(Args...))function;
return f(read<Args>(Data, Ns + 1)...);// +1 because indices is zero-based
}
template<typename R, typename... Args>
R myFunction(void *Data, void *function) {
return myFunctionImpl< R, Args... >( Data, function, typename make_indices<sizeof...(Args)>::type() );
}
EDIT: How does it work? First, we determine the size of the argument pack Args through sizeof.... make_indices<N>::type then expands into indices<0,1,2,...,N-1>. It is given as an additional parameter to the implementation function (from the forwarder who just creates a dummy instance), hence argument deduction kicks in on the implementation function's side and puts the generated indices into the argument pack Ns.
The implementation function now has two argument packs with the same size, namely Args and Ns. When expanded through the ellipsis ..., the ellipsis expands the whole expression that it's applied to and it expands all parameter packs in parallel! In the above example that expression is read<Args>(Data, Ns+1), which nicely expands into the OPs pseudo-code.

Related

Calling a common method of tuple elements

Say I have a tuple of types T1,...,TN that implement some method, apply().
How do I define a function that takes this tuple and some initial element, and returns the chained call of apply() on this element?
For example:
template <typename... Args, typename Input>
auto apply(std::tuple<Args...> const &tpl, Input x) {
// return ???
}
// simple example
struct Sqr {
static int apply(int x) { return x * x; }
};
enum class Choice {
One,
Two,
};
struct Choose {
static int apply(Choice choice) {
switch (choice) {
case Choice::One:
return 1;
case Choice::Two:
return 2;
}
}
};
void test() {
auto tpl = std::tuple(Sqr{}, Choose{});
assert(apply(tpl, Choice::One) == 1);
assert(apply(tpl, Choice::Two) == 4);
}
I tried to use fold expressions, and variations of answers from: Template tuple - calling a function on each element but couldn't get anything to compile.
The main difference is that I need each invocation's result as the input for the next one.
Concretely, I tried the following, which failed because it calls each argument with the initial value:
template <typename... Args, typename Input>
auto apply(std::tuple<Args...> const &tpl, Input x) {
return std::apply([&x](auto &&... args) {
return (..., args.apply(x));
}, tpl);
}
Clarifications and assumptions:
I want the methods to be called in a specific order - last to first - similarly to mathematical function composition.
(f * g)(x) := f(g(x))
The input and output types of each tuple argument are not constricted. The only assumption is that consecutive arguments agree on the corresponding types.
There may be snazzier C++17 ways of doing it, but there is always good old-fashioned partially-specialized recursion. We'll make a struct that represents your recursive algorithm, and then we'll build a function wrapper around that struct to aid in type inference. First, we'll need some imports.
#include <tuple>
#include <utility>
#include <iostream> // Just for debugging later :)
Here's our structure definition.
template <typename Input, typename... Ts>
struct ApplyOp;
Not very interesting. It's an incomplete type, but we're going to provide specializations. As with any recursion, we need a base case and a recursive step. We're inducting on the tuple elements (you're right to think of this as a fold-like operation), so our base case is when the tuple is empty.
template <typename Input>
struct ApplyOp<Input> {
Input apply(Input x) {
return x;
}
};
In this case, we just return x. Computation complete.
Now our recursive step takes a variable number of arguments (at least one) and invokes .apply.
template <typename Input, typename T, typename... Ts>
struct ApplyOp<Input, T, Ts...> {
auto apply(Input x, const T& first, const Ts&... rest) {
auto tail_op = ApplyOp<Input, Ts...>();
return first.apply(tail_op.apply(x, rest...));
}
};
The tail_op is our recursive call. It instantiates the next version of ApplyOp. There are two apply calls in this code. first.apply is the apply method in the type T; this is the method you control which determines what happens at each step. The tail_op.apply is our recursive call to either another version of this apply function or to the base case, depending on what Ts... is.
Note that we haven't said anything about tuples yet. We've just taken a variadic parameter pack. We're going to convert the tuple into a parameter pack using an std::integer_sequence (More specifically, an std::index_sequence). Basically, we want to take a tuple containing N elements and convert it to a sequence of parameters of the form
std::get<0>(tup), std::get<1>(tup), ..., std::get<N-1>(tup)
So we need to get an index sequence from 0 up to N-1 inclusive (where N-1 is our std::tuple_size).
template <typename Input, typename... Ts>
auto apply(const std::tuple<Ts...>& tpl, Input x) {
using seq = std::make_index_sequence<std::tuple_size<std::tuple<Ts...>>::value>;
// ???
}
That complicated-looking type alias is building our index sequence. We take the tuple's size (std::tuple_size<std::tuple<Ts...>>::value) and pass it to std::make_index_sequence, which gives us an std::index_sequence<0, 1, 2, ..., N-1>. Now we need to get that index sequence as a parameter pack. We can do that with one extra layer of indirection to get type inference.
template <typename Input, typename... Ts, std::size_t... Is>
auto apply(const std::tuple<Ts...>& tpl, Input x, std::index_sequence<Is...>) {
auto op = ApplyOp<Input, Ts...>();
return op.apply(x, std::get<Is>(tpl)...);
}
template <typename Input, typename... Ts>
auto apply(const std::tuple<Ts...>& tpl, Input x) {
using seq = std::make_index_sequence<std::tuple_size<std::tuple<Ts...>>::value>;
return apply(tpl, x, seq());
}
The second apply is the one outside users call. They pass a tuple and an input value. Then we construct an std::index_sequence of the appropriate type and pass that to the first apply, which uses that index sequence to access each element of the tuple in turn.
Complete, runnable example
The main difference is that I need each invocation's result as the
input for the next one.
Apply fold-expression to assignment operator
template <typename... Args, typename Input>
auto my_apply(std::tuple<Args...> const &tpl, Input x) {
return std::apply([&x](auto... op) {
return ((x = op.apply(x)), ...);
}, tpl);
}
Demo
You can introduce an dummy variable for reverse order
template <typename... Args, typename Input>
auto my_apply(std::tuple<Args...> const &tpl, Input x) {
return std::apply([&x](auto... op) {
int dummy;
(dummy = ... = ((x = op.apply(x)), 0));
return x;
}, tpl);
}
Demo
One way without recursion is to use fold expression.
Unfortunately, there is no call composition operator folding.
But you might create custom type and divert regular operator:
template <typename T>
struct Wrapper
{
T t;
};
// Deduction guide, not needed in C++20
template <typename T> Wrapper(T) -> Wrapper<T>;
// Then the operator with changed semantic
template <typename T1, typename T2>
auto operator+(const Wrapper<T1>& lhs, const Wrapper<T2>& rhs)
{
return Wrapper{lhs.t.apply(rhs.t)};
}
template <typename T1, typename T2>
auto operator-(const Wrapper<T1>& lhs, const Wrapper<T2>& rhs)
{
return Wrapper{rhs.t.apply(lhs.t)};
}
// And now, the function with fol expression
template <typename... Args, typename Input>
auto my_apply(std::tuple<Args...> const &tup, Input x) {
return std::apply([&](auto&...args){
return (Wrapper<const Args&>{args} + ... + Wrapper<Input&>{x});
}, tup).t;
}
template <typename... Args, typename Input>
auto my_apply_rev(std::tuple<Args...> const &tup, Input x) {
return std::apply([&](auto&...args){
return (Wrapper<Input&>{x} - ... - Wrapper<const Args&>{args});
}, tup).t;
}
Usage similar to
// std::size(std::to_string(10 * 10));
my_apply(std::tuple{ LengthOp{}, ToStringOp{}, SquareOp{}}, 10);
my_apply_rev(std::tuple{ SquareOp{}, ToStringOp{}, LengthOp{}}, 10);
Demo

Definition and Initialization of a tuple whose components are of the same templated class, but with different specialisations

I am new to c++ metaprogramming. I tried to look at other answers, but I was not able to find one that could suit my problem.
Or simply I was not able to apply it to my case.
Here I will post a simplified version of the code, to highlight the main features which I would like to obtain.
What I would like to achieve, is the construction of a std::tuple of dimension N (N known at compile-time),
whose components type is given by a template class, MyType, depending on two parameters M and N.
M is fixed, while the type of the tuple component i is actually MyType<M,i>, for i=0,...,N.
Since I have to define recursively a tuple of these types, I have considered the DefineType template.
// general definition
template<Integer M, Integer N>
struct DefineType
{
using rest = typename DefineType<M, N-1>::type;
using type = decltype(std::tuple_cat(std::declval< std::tuple< MyType<M,N>>>(),
std::declval<rest>() ));
};
// specialization for N=0
template<Integer M>
struct DefineType<M,0>
{
using type = typename std::tuple< MyType<M,0> >;
};
This should produce the following types:
DefineType< M, N=0 >: std::tuple< MyType< M,0 > > ;
DefineType< M, N=1 >: std::tuple< MyType< M,0 >, MyType< M,1 > > ;
DefineType< M, N=2 >: std::tuple< MyType< M,0 >, MyType< M,1 > , MyType< M,2 > > ;
and so on, up to a general N.
Then I would like also to initialize a tuple of this kind, based on something which I call param of type Param. For doing this,
I write a code of this kind:
// general definition
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return std::tuple_cat(std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param) ) ;
}
// specialization for N=0
template<Integer M>
typename DefineType<M,0>::type MyClass(Param param)
{
return std::tuple<MyType<M, 0>>(MyType<M, 0>(param));
}
Finally in the main:
int main()
{
// M and N given
const auto myobject=MyClass<M,N>(param);
}
The code is not compiling, complaining that I am initializing too many times DefineType<M,N>. Basically N does not reach the base-case, with N=0. I do not get why...So for sure the recursive type definition is wrong. But, in addition to this, maybe there are other errors that I do not see. I hope you can help me in understanding how to do this. I apologize, but meta programming is very new (and difficult) to me.
Thank you.
Given the definitions
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return std::tuple_cat(std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param) ) ;
}
template<Integer M>
typename DefineType<M,0>::type MyClass(Param param)
{
return std::tuple<MyType<M, 0>>(MyType<M, 0>(param));
}
what you have is two overloaded distinct function templates. The second is not a "partial specialization" of the first because there is no such thing a function template partial specialization, only class template specializations. (And so the call MyClass<M,N-1>(param) can't possibly match the second template, even if it had been previously declared, since the second one only accepts one template argument, meaning the first template is infinitely recursive.)
One solution could be to use a helper class template:
namespace MyClass_detail {
template<Integer M, Integer N>
struct helper {
static typename DefineType<M,N>::type build(const Param& param)
{
return std::tuple_cat(
std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param));
}
};
template<Integer M>
struct helper<M, 0> {
static typename DefineType<M,0>::type build(const Param& param)
{
return std::tuple<MyType<M, 0>>(MyType<M, 0>(param));
}
};
}
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return MyClass_detail::helper<M,N>::build(Param);
}
Though I would recommend taking advantage of std::make_integer_sequence. (This is a C++14 feature, and I see your question is tagged C++11. If you can't use C++14 or later, a search should turn up some replacement implementations for make_integer_sequence and related tools that can be used in C++11.)
#include <utility>
#include <tuple>
namespace MyClass_detail {
template<Integer M, Integer N, Integer ...Inds>
auto MyClass_helper(const Param &param, std::integer_sequence<Integer, Inds...>)
{
return std::make_tuple(MyType<M, N-Inds>(param)...);
}
}
template<Integer M, Integer N>
auto MyClass(Param param)
{
return MyClass_detail::MyClass_helper<M,N>(
param, std::make_integer_sequence<Integer, N+1>{});
}
// And if DefineType is wanted for other uses:
template<Integer M, Integer N>
using DefineType = decltype(MyClass<M,N>(std::declval<Param>()));
See the full working demo on coliru.
I see two problems in your code.
(1) you say that you want that
DefineType< M, N=2 > is std::tuple< MyType< M,0 >, MyType< M,1 > , MyType< M,2 > >
but writing
using type = decltype(std::tuple_cat(std::declval< std::tuple< MyType<M,N>>>(),
std::declval<rest>() ));
inside DefineType, you get the opposite order; you obtain that
DefineType< M, N=2 > is std::tuple<MyType<M, 2>, MyType<M, 1> , MyType<M, 0>>
If you want the order from zero to N, you have to define, in DefineType, before the rest and then the N element; I mean
using type = decltype(std::tuple_cat(
std::declval<rest>(),
std::declval<std::tuple<MyType<M,N>>>() ));
(2) The recursion for MyClass() function doesn't works because in your recursive version call the same MyClass() ever with two template parameters
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return std::tuple_cat(std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param) ) ;
} // you call the second parameter .........^^^
// also when N is 1 (and N-1 is 0)
so the base-case (defined with only one template parameter) never matches.
Unfortunately partial template specialization doesn't works for template functions, so you can use partial template specialization of structs (see aschepler's answer) or, if you prefer, SFINAE to enable/disable the two versions of MyClass() according the value of N.
I propose the following solution
// specialization for N == 0
template <Integer M, Integer N>
typename std::enable_if<(N == 0), typename DefineType<M,0>::type>::type
MyClass(Param param)
{ return std::tuple<MyType<M, 0>>(MyType<M, 0>(param)); }
// general definition
template <Integer M, Integer N>
typename std::enable_if<(N > 0u), typename DefineType<M,N>::type>::type
MyClass(Param param)
{
return std::tuple_cat(
MyClass<M,N-1>(param),
std::tuple<MyType<M,N>>(MyType<M,N>(param)) );
}
Observe that now the ground case (N == 0) has two template parameter but is enabled only when N is zero. The other case in enabled only when N > 0.
Observe also that you have to write before the ground case version because it is used by the recursive version.
Observe also that I've switched the order of rest/actual type.
If you can use C++14, so std::make_index_sequence/std::index_sequence, I strongly suggest to avoid recursion and to follow the aschepler's suggestion.
You can also avoid recursion for the DefineType itself using specialization as follows
template <Integer, Integer N, typename = std::make_index_sequence<N+1u>>
struct DefineType;
template <Integer M, Integer N, std::size_t ... Is>
struct DefineType<M, N, std::index_sequence<Is...>>
{ using type = std::tuple<MyType<M, Is>...>; };
The following is a full compiling C++14 example
#include <tuple>
#include <type_traits>
using Integer = std::size_t;
using Param = int;
template <Integer M, Integer N>
struct MyType
{ MyType (Param) {} };
template <Integer, Integer N, typename = std::make_index_sequence<N+1u>>
struct DefineType;
template <Integer M, Integer N, std::size_t ... Is>
struct DefineType<M, N, std::index_sequence<Is...>>
{ using type = std::tuple<MyType<M, Is>...>; };
template <Integer M, Integer N>
std::enable_if_t<(N == 0), typename DefineType<M,0>::type>
MyClass(Param param)
{ return std::tuple<MyType<M, 0>>(MyType<M, 0>(param)); }
// general definition
template <Integer M, Integer N>
std::enable_if_t<(N > 0u), typename DefineType<M,N>::type>
MyClass(Param param)
{
return std::tuple_cat(
MyClass<M,N-1>(param),
std::tuple<MyType<M,N>>(MyType<M,N>(param)) );
}
int main ()
{
using t0 = typename DefineType<42u, 0u>::type;
using u0 = std::tuple<MyType<42u, 0u>>;
using t1 = typename DefineType<42u, 1u>::type;
using u1 = std::tuple<MyType<42u, 0u>, MyType<42u, 1u>>;
using t2 = typename DefineType<42u, 2u>::type;
using u2 = std::tuple<MyType<42u, 0u>, MyType<42u, 1u>, MyType<42u, 2u>>;
static_assert( std::is_same<t0, u0>::value, "!" );
static_assert( std::is_same<t1, u1>::value, "!" );
static_assert( std::is_same<t2, u2>::value, "!" );
auto const myobject = MyClass<42u, 2u>(12);
}

Function with a fixed amount of parameters determined by an integer

I have a class with a template that accepts an integer:
template <unsigned int N>
class Example {};
I'm looking for a way to define a (member)function that accepts some amount of Example objects as arguments. The amount is to be determined by N, so the function would be used like this:
Function(Example<2>(), Example<2>());
Function(Example<3>(), Example<3>(), Example<3>());
What I tried so far:
Using an initializer list, one is able to pass a set of objects to the function:
template <unsigned int N>
void Function(std::initializer_list<Example<N>> list);
//...
Function({Example<2>(), Example<2>()});
However, the problem besides the fact that really only one argument is passed(the list), is that with this method any number of arguments can be used:
Function({Example<2>()});
I also tried using a variadic function:
template <unsigned int N>
void Function(Example<N> e...)
{
va_list args;
va_start(args, e);
//...
}
Function(Example<2>(), Example<2>());
This makes it possible to use real parameters, but the problem of using any number of arguments remains, and it's not possible to know how many arguments were actually passed.
Assuming you want the number of arguments to be deduced from the Example<N> type, and that all Example<I> should share the same such N, a C++17 solution might be
template <unsigned int... I>
auto Function( Example<I>... ) ->
std::enable_if_t<( ( I == sizeof...(I) ) && ... )>
{
// or static_assert() if you always want an error
}
Make Function a variadic template and use std::enable_if_t to constrain your it:
Some IsExample trait can be used to make sure that all arguments are instances of Example
sizeof...(pack) can be used to get the size of the parameter pack
template <unsigned int N, typename... Ts>
auto Function(Ts... xs)
-> std::enable_if_t<(IsExample<Ts>::value && ...)
&& (sizeof...(Ts) == N)>
{
}
live example on wandbox
You should utilize variadic function template with static_assert. Unlike approaches involving enable_if this one will produce a readable error message if incorrect arguments are passed.
template<unsigned int ... I>
void Function(Example<I>... items)
{
static_assert
(
true && (... && (static_cast<unsigned int>(sizeof...(I)) == I))
, "This function accepts N arguments of type Example<N>"
);
}
Online compiler
There are many answers that cover SFINAE friendly based constraints, but I don't like placing my SFINAE in the return value:
template <unsigned int... Is,
std::enable_if_t<( ( Is == sizeof...(Is) ) && ... ), bool> = true
>
void Function( Example<Is>... examples )
{
// code
}
or
template<bool b>
using test_requirement = std::enable_if_t<b, bool>;
template <unsigned int... Is,
test_requirement<( ( Is == sizeof...(Is) ) && ... )> = true
>
void Function( Example<Is>... examples )
{
// code
}
+1 for the Massimiliano Janes's elegant solution.
Unfortunately use folding so works only for C++17.
To test, with C++11/C++14, that all I are equals to sizeof...(I) (and maybe that sizeof...(I) is equal to N, where N is the class template argument), it's enough test that a variadic type, that receive unsigned values, is the same type with a different order of values.
I mean: declaring a trivial struct as
template <std::size_t ... Is>
struct IList;
the test can be
std::is_same<IList<N, sizeof...(Is), Is...>,
IList<sizeof...(Is), Is..., N>>::value
Starting from C++14 it's possible to use std::index_sequence instead of IList.
So Example can be written as
template <unsigned int N>
struct Example
{
template <unsigned int ... Is>
auto Function (Example<Is> ...)
-> typename std::enable_if<
std::is_same<IList<N, sizeof...(Is), Is...>,
IList<sizeof...(Is), Is..., N>>::value>::type
{ /* do something */ }
};
The following is a example of use (but remember to include <type_traits>)
int main()
{
Example<1U> e1;
Example<2U> e2;
// e1.Function(); // error
e1.Function(Example<1>{}); // compile
//e1.Function(Example<1>{}, Example<1>{}); // error
// e2.Function(); // error
//e2.Function(Example<2>{}); // error
e2.Function(Example<2>{}, Example<2>{}); // compile
//e2.Function(Example<2>{}, Example<2>{}, Example<2>{}); // error
}

C++ variadic template arguments method to pass to a method without variadic arguments

I have the following question, I really can't compile from all the questions and articles researched:
In C++, is it possible to have a method with variadic template arguments that specify types of arguments (as a meta-description type for parameters of in, out, in/out of a certain type, to be passed by value, by address etc.), to loop through these variadic arguments in order to instantiate variables of specified types, and be passed these variables to functions specified by a pointer in a template parameter, but these functions not having variadic parameters?
EDIT 1
I try here to detail, as pseudocode:
template <decltype(*Type::*Method), typename... Parameters>
static bool ExecuteMethod(JSContext *cx, unsigned argc, JS::Value *vp)
{
JS::CallArgs args = CallArgsFromVp(argc, vp);
loop through Parameters
{
Parameters[i]::Type p[i] <-- args[i];
}
ReturnType r = Method(p[0], p[1], p[2] .. p[n]); // the method does not have variadic parameters
...
}
where Method might be like:
int(*GetColor) ( int16 *color);
int(*GetFile) ( FilePath &file );
int(*WriteDocument) ( const FilePath &file, const char *fileFormatName, bool askForParms);
etc.
This comes out of wrapping needs.
The challenge is something missing in C++, reflection as in .net.
It is possible to instance an array of heterogeneous objects by looping through the variadic arguments somehow? Probably.
But how pass them to methods having no variadic arguments? I think it is not possible to assign that array of objects to functions like these three above without explicit wrappers, isn't it?
EDIT 2
I've got a lot of feed-back, but it is clear I was not specific enough.
I did not detailed too much because I've got complains in the past for being too specific. Indeed, I do not have easy implementations and I am a generic guy, not lazy, but I try to make a latter development faster.
Here is the source of the problem: I need to wrap Adobe Illustrator API, which exposes hundreds if not thousands of pointers to functions grouped in structs, called suites.
I try to have a javascript engine using SpiderMonkey.
I use Visual Studio 2015 compiler.
My approach is as follows:
I have several classes to wrap the API in order to add to SpiderMonkey's engine objects for all the suites. Each SpiderMonkey class, could be called as jsData, wraps a data type of Adobe SDK, or a suite, jsSuite.
So far, I have used templates because SpiderMonkey forces me to add each function to its custom objects with a specific signature, like this:
bool jsAIDocumentSuite::WriteDocument(JSContext *cx, unsigned argc, JS::Value *vp)
{
...
}
and adding it to the custom object would be done like this:
const JSFunctionSpec jsAIDocumentSuite::fFunctions[] = {
...
JS_FN("WriteDocument", jsAIDocumentSuite::WriteDocument, 3, 0),
...
}
JS_FN is a SpiderMonkeyMacro.
Actually, this is, so far, less than 10% of the Adobe SDK.
The most are getters and setters with one parameter, passed by value or address or pointer, so I have replaced them by a generic function, like this:
template <typename jsType, typename jsReturnType, typename ReturnPrivateType = jsReturnType::PrivateType, typename jsParamType, typename ParamPrivateType = jsParamType::PrivateType, ReturnPrivateType(*Type::*Method)(ParamPrivateType&)>
static bool GetByRefMethod(JSContext *cx, unsigned argc, JS::Value *vp)
{
JS::CallArgs args = CallArgsFromVp(argc, vp);
try
{
ReturnPrivateType result;
ParamPrivateType ppt;
if (jsType::Suite() && (jsType::Suite()->*Method))
result = (jsType::Suite()->*Method)(ppt);
else
return false; // TODO throw a meaningful error
if ((jsReturnType::IsNoError(result)) && (argc > 0) && (args[0].isObject()))
{
JSObject *obj = &args[0].toObject();
JSObject *value = NULL;
if (!jsParamType::FromAIObject<jsParamType>(cx, &ppt, value))
return false;
if (!value)
return false;
jsProperty::SetProperty(cx, &obj, "value", value, true);
}
JSObject *obj = JS_NewObject(cx, &jsDataClass<jsReturnType>::fClass);
JS_SetPrivate(obj, new ReturnPrivateType(result));
args.rval().setObject(*obj);
}
EXCEPTION_CATCH_CONVERT();
return true;
}
A bit complicated, isn't it?
What is relevant, above, is:
The args variable holds the SpiderMonkey parameters passed in by its engine
Only one argument is passed here, ppt
The return type is one value, so it is easy to be handled
I use macros to inject the method in its variants (several short forms too, not so interesting here):
JS_FN(#GET_METHOD, (js##TYPE::GetByRefMethod<js##TYPE, RETURN_JS_TYPE, RETURN_PRIVATE_TYPE, PARAM_JS_TYPE, PARAM_PRIVATE_TYPE, &TYPE::GET_METHOD>), 1, 0)
I wish to be able to handle variable arguments, according to the statistics more philosophical, but interesting. The idea would be opposite to the C++, probably, and not as expected.
How would I expect it:
I wish to add variadic parameters meta-information, like:
template
static bool Method(JSContext *cx, unsigned argc, JS::Value *vp)
{
JS::CallArgs args = CallArgsFromVp(argc, vp);
try
{
ReturnPrivateType result;
*1st challenge: Loop through the variadic list of meta-parameters and create their corresponding object instances here and initialize the IN ones with values from the *args* collection passed by the SpiderMonkey engine*
if (jsType::Suite() && (jsType::Suite()->*Method))
result = (jsType::Suite()->*Method)(*2nd challenge: pass arguments here: probably by using a variadic macro?*);
else
return false; // TODO throw a meaningful error
if ((jsReturnType::IsNoError(result)) && (argc > 0) && (args[0].isObject()))
{
JSObject *obj = &args[0].toObject();
JSObject *value = NULL;
if (!jsParamType::FromAIObject<jsParamType>(cx, &ppt, value))
return false;
if (!value)
return false;
jsProperty::SetProperty(cx, &obj, "value", value, true);
}
JSObject *obj = JS_NewObject(cx, &jsDataClass<jsReturnType>::fClass);
JS_SetPrivate(obj, new ReturnPrivateType(result));
args.rval().setObject(*obj);
}
EXCEPTION_CATCH_CONVERT();
return true;
}
As you can see, it is not as C++ expected, it is a bit reversed, by trying to avoid writing templates to deduct the parameters, here, I know the parameters first and try to write a code to generate the right parameters by knowing their meta-information first and I have a clear set of types and I promise to write the right code to generate the correct wrappers. I don't need to validate much regarding the data of the parameters, as things are mostly passed without a huge business logic in the process.
EDIT 3
About the parameters meta-information, I could write a few types with statics to specify the data type of the parameter, whether it is a return type, whether it is an IN, an OUT or an IN/OUT parameter, its jsType etc..
They would be the variadic list of the template parameters function above.
I still am having some difficulty understanding exactly what you want to do, but this should let you call a function(without variardic parameters) using a variardic template function, getting the parameters from an array and allowing a conversion operation to apply to each parameter before being passed to the function:
#include <functional>
template<typename T, typename JST> T getParam(const JST& a)
{
//Do whatever conversion necessary
return a;
}
namespace detail
{
template<typename R, typename... Args, int... S> R jsCaller(std::function<R(Args...)> f, seq<S...>, const JS::CallArgs& args)
{
return f(getParam<Args, /*Whatever type should go here */>(args[S])...);
}
}
//Actually use this to call the function and get the result
template<typename R, typename... Args> R jsCall(std::function<R(Args...)> f, const JS::CallArgs& args)
{
return detail::jsCaller(f, GenSequence<sizeof...(Args)>(), args);
}
Where GenSequence extends seq<0, 1, 2, ... , N - 1> and can be implemented as follows:
template<int... N>
struct seq {};
template<int N, int... S>
struct gens : gens<N-1, N-1, S...> {};
template<int... S>
struct gens<0, S...>
{
typedef seq<S...> type;
};
template<int N> using GenSequence<N> = typename gens<N>::type;
This creates a parameter pack of integers, and expands the function call using them- See this question.
You can call your method using jsCall:
Result r = jsCall((Method), args);
Assuming Method can be converted to std::function- if not, you can still do it by making a lambda which conforms to std::function. Does this solve the problem?
[Continued from part 1: https://stackoverflow.com/a/35109026/5386374 ]
There is an issue, however. We had to change the way our code is written to accomodate ExecuteMethod(), which may not always be possible. Is there a way around that, so that it functions exactly the same as your previously specified ExecuteMethod(), and doesn't need to take the variable it modifies as a macro parameter? The answer is... yes!
// Variadic function-like macro to automatically create, use, and destroy functor.
// Uncomment whichever one is appropriate for the compiler used.
// (The difference being that Visual C++ automatically removes the trailing comma if the
// macro has zero variadic arguments, while GCC needs a hint in the form of "##" to tell
// it to do so.)
// Instead of a do...while structure, we can just use a temporary Executor directly.
// MSVC:
// #define ExecuteMethod(M, ...) Executor<decltype(&M), decltype(&M)>{}(M, __VA_ARGS__)
// GCC:
#define ExecuteMethod(M, ...) Executor<decltype(&M), decltype(&M)>{}(M, ##__VA_ARGS__)
// For your example function WriteDocument(), defined as
// int WriteDocument(const FilePath &file, const char *fileFormatName, bool askForParms);
bool c = ExecuteMethod(WriteDocument, file, fileFormatName, askForParams);
This is all well and good, but there is one more change we can make to simplify things without impacting performance. At the moment, this functor can only take function pointers (and maybe lambdas, I'm not familiar with their syntax), not other types of function objects. If this is intended, it means that we can rewrite it to do away with the first template parameter (the entire signature), since the second and third parameters are themselves components of the signature.
// Default functor.
template<typename... Ts>
struct Executor { };
// General case.
template<typename ReturnType, typename... Params>
struct Executor<ReturnType (*)(Params...)> {
private:
// Instead of explicitly taking M as a parameter, create it from
// the other parameters.
using M = ReturnType (*)(Params...);
public:
// Parameter match:
bool operator()(M method, Params... params) {
ReturnType r = method(params...);
// ...
}
// Parameter mismatch:
template<typename... Invalid_Params>
bool operator()(M method, Invalid_Params... ts) {
// Handle parameter type mismatch here.
}
};
// Special case to catch void return type.
template<typename... Params>
struct Executor<void (*)(Params...)> {
private:
// Instead of explicitly taking M as a parameter, create it from
// the other parameters.
using M = void (*)(Params...);
public:
// Parameter match:
bool operator()(M method, Params... params) {
method(params...);
// ...
}
// Parameter mismatch:
template<typename... Invalid_Params>
bool operator()(M method, Invalid_Params... ts) {
// Handle parameter type mismatch here.
}
};
// Variadic function-like macro to automatically create, use, and destroy functor.
// Uncomment whichever one is appropriate for the compiler used.
// (The difference being that Visual C++ automatically removes the trailing comma if the
// macro has zero variadic arguments, while GCC needs a hint in the form of "##" to tell
// it to do so.)
// Instead of a do...while structure, we can just use a temporary Executor directly.
// MSVC:
// #define ExecuteMethod(M, ...) Executor<decltype(&M)>{}(M, __VA_ARGS__)
// GCC:
#define ExecuteMethod(M, ...) Executor<decltype(&M)>{}(M, ##__VA_ARGS__)
// Note: If your compiler doesn't support C++11 "using" type aliases, replace them
// with the following:
// typedef ReturnType (*M)(Params...);
This results in cleaner code, but, as mentioned, limits the functor to only accepting function pointers.
When used like this, the functor expects parameters to be an exact match. It can handle reference-ness and cv-ness correctly, but may have issues with rvalues, I'm not sure. See here.
As to how to use this with your JSContext... I'm honestly not sure. I haven't learned about contexts yet, so someone else would be more helpful for that. I would suggest checking if one of the other answers here would be more useful in your situation, in all honesty.
Note: I'm not sure how easy it would be to modify the functor to work if its function parameter is a functor, lambda, std::function, or anything of the sort.
Note 2: As before, I'm not sure if there would be any negative effects on performance for doing something like this. There's likely a more efficient way, but I don't know what it would be.
I came up with the following C++11 solution, which gives the basic idea. It could very easily be improved, however, so I welcome suggestions. Live test here.
#include <iostream>
#include <tuple>
using namespace std;
// bar : does something with an arbitrary tuple
// (no variadic template arguments)
template <class Tuple>
void bar(Tuple t)
{
// .... do something with the tuple ...
std::cout << std::tuple_size<Tuple>::value;
}
// foo : takes a function pointer and an arbitrary number of other
// arguments
template <class Func, typename... Ts>
void foo(Func f, Ts... args_in)
{
// construct a tuple containing the variadic arguments
std::tuple<Ts...> t = std::make_tuple(args_in...);
// pass this tuple to the function f
f(t);
}
int main()
{
// this is not highly refined; you must provide the types of the
// arguments (any suggestions?)
foo(bar<std::tuple<int, const char *, double>>, 123, "foobar", 43.262);
return 0;
}
Edit: After seeing your "Edit 2", I don't believe this is the proper solution. Leaving it up for reference, though.
I believe I've found a potential solution that catches reference-ness, too. Scroll down to the bottom, to the "Edit 4" section.
If you're asking whether it's possible to dynamically check template argument types, you can. I'll start with a general example of how to use std::true_type and std::false_type to overload based on whether a specified condition is met, then move on to your problem specifically. Consider this:
#include <type_traits>
namespace SameComparison {
// Credit for the contents of this namespace goes to dyp ( https://stackoverflow.com/a/20047561/5386374 )
template<class T, class...> struct are_same : std::true_type{};
template<class T, class U, class... TT> struct are_same<T, U, TT...> :
std::integral_constant<bool, std::is_same<T, U>{} && are_same<T, TT...>{} >{};
} // namespace SameComparison
template<typename T> class SomeClass {
public:
SomeClass() = default;
template<typename... Ts> SomeClass(T arg1, Ts... args);
~SomeClass() = default;
void func(T arg1);
template<typename U> void func(U arg1);
template<typename... Ts> void func(T arg1, Ts... args);
template<typename U, typename... Ts> void func(U arg1, Ts... args);
// ...
private:
template<typename... Ts> SomeClass(std::true_type x, T arg1, Ts... args);
template<typename... Ts> SomeClass(std::false_type x, T arg1, Ts... args);
// ...
};
// Constructors:
// -------------
// Public multi-argument constructor.
// Passes to one of two private constructors, depending on whether all types in paramater pack match T.
template<typename T> template<typename... Ts> SomeClass<T>::SomeClass(T arg1, Ts... args) :
SomeClass(SameComparison::are_same<T, Ts...>{}, arg1, args...) { }
// All arguments match.
template<typename T> template<typename... Ts> SomeClass<T>::SomeClass(std::true_type x, T arg1, Ts... args) { }
// One or more arguments is incorrect type.
template<typename T> template<typename... Ts> SomeClass<T>::SomeClass(std::false_type x, T arg1, Ts... args) {
static_assert(x.value, "Arguments wrong type.");
}
/*
Note that if you don't need to use Ts... in the parameter list, you can combine the previous two into a single constructor:
template<typename T> template<bool N, typename... Ts> SomeClass<T>::SomeClass(std::integral_constant<bool, N> x, T arg1, Ts... args) {
static_assert(x.value, "Arguments wrong type.");
}
x will be true_type (value == true) on type match, or false_type (value == false) on type mismatch. Haven't thoroughly tested this, just ran a similar function through an online compiler to make sure it could determine N.
*/
// Member functions:
// -----------------
// Single argument, type match.
template<typename T> void SomeClass<T>::func(T arg1) {
// code
}
// Single argument, type mismatch.
// Also catches true_type from multi-argument functions after they empty their parameter pack, and silently ignores it.
template<typename T> template<typename U> void SomeClass<T>::func(U arg1) {
if (arg1 != std::true_type{}) {
std::cout << "Argument " << arg1 << " wrong type." << std::endl;
}
}
// Multiple arguments, argument 1 type match.
template<typename T> template<typename... Ts> void SomeClass<T>::func(T arg1, Ts... args) {
func(arg1);
func(args...);
// func(SameComparison::are_same<T, Ts...>{}, vals...);
}
// Multiple arguments, argument 1 type mismatch.
template<typename T> template<typename U, typename... Ts> void SomeClass<T>::func(U arg1, Ts... args) {
// if (arg1 != std::true_type{}) {
// std::cout << "Argument " << arg1 << " wrong type." << std::endl;
// }
func(vals...);
}
First, SameComparison::are_same there is an extension of std::is_same, that applies it to an entire parameter pack. This is the basis of the check, with the rest of the example showing how it can be used. The lines commented out of the last two functions show how it could be applied there, as well.
Now, onto your problem specifically. Since you know what the methods are, you can make similar comparison structs for them.
int (*GetColor) ( int16_t *color);
int(*GetFile) ( FilePath &file );
int(*WriteDocument) ( const FilePath &file, const char *fileFormatName, bool askForParms);
Could have...
namespace ParameterCheck {
template<typename T, typename... Ts> struct parameter_match : public std::false_type {};
// Declare (GetColor, int16_t*) valid.
template<> struct parameter_match<int (*)(int16_t*), int16_t*> : public std::true_type {};
// Declare (GetFile, FilePath&) valid.
// template<> struct parameter_match<int (*)(FilePath&), FilePath&> : public std::true_type {}; // You'd think this would work, but...
template<> struct parameter_match<int (*)(FilePath&), FilePath> : public std::true_type {}; // Nope!
// For some reason, reference-ness isn't part of the templated type. It acts as if it was "template<typename T> void func(T& arg)" instead.
// Declare (WriteDocument, const FilePath&, const char*, bool) valid.
// template<> struct parameter_match<int (*)(const FilePath&, const char*, bool), const FilePath, const char*, bool> : public std::true_type {};
// template<> struct parameter_match<int (*)(const FilePath&, const char*, bool), const FilePath&, const char*, bool> : public std::true_type {};
template<> struct parameter_match<int (*)(const FilePath&, const char*, bool), FilePath, const char*, bool> : public std::true_type {};
// More reference-as-template-parameter wonkiness: Out of these three, only the last works.
} // namespace ParameterCheck
Here, we make a general-case struct that equates to std::false_type, then specialise it so that specific cases are true_type instead. What this does is tell the compiler, "These parameter lists are good, anything else is bad," where each list starts with a function pointer and ends with the arguments to the function. Then, you can do something like this for your caller:
// The actual calling function.
template<typename Func, typename... Ts> void caller2(std::true_type x, Func f, Ts... args) {
std::cout << "Now calling... ";
f(args...);
}
// Parameter mismatch overload.
template<typename Func, typename... Ts> void caller2(std::false_type x, Func f, Ts... args) {
std::cout << "Parameter list mismatch." << std::endl;
}
// Wrapper to check for parameter mismatch.
template<typename Func, typename... Ts> void caller(Func f, Ts... args) {
caller2(ParameterCheck::parameter_match<Func, Ts...>{}, f, args...);
}
As for return type deduction... that depends on where you want to deduce it:
Determine variable type from contents: Use auto when declaring the variable.
Determine return type from passed function return type: If your compiler is C++14-compatible, that's easy. Just use auto. [VStudio 2015 and GCC 4.8.0 (with -std=c++1y) are compatible with auto return type.]
The former can be done like this:
int i = 42;
int func1() { return 23; }
char func2() { return 'c'; }
float func3() { return -0.0f; }
auto a0 = i; // a0 is int.
auto a1 = func1(); // a1 is int.
auto a2 = func2(); // a2 is char.
auto a3 = func3(); // a3 is float.
The latter, however, is more complex.
std::string stringMaker() {
return std::string("Here, have a string!");
}
int intMaker() {
return 5;
}
template<typename F> auto automised(F f) {
return f();
}
// ...
auto a = automised(stringMaker); // a is std::string.
auto b = automised(intMaker); // a is int.
If your compiler isn't compatible with auto or decltype(auto) return type... well, it's a bit more verbose, but we can do this:
namespace ReturnTypeCapture {
// Credit goes to Angew ( https://stackoverflow.com/a/18695701/5386374 )
template<typename T> struct ret_type;
template<typename RT, typename... Ts> struct ret_type<RT (*)(Ts...)> {
using type = RT;
};
} // namespace ReturnTypeCapture
// ...
std::string f1() {
return std::string("Nyahaha.");
}
int f2() {
return -42;
}
char f3() {
return '&';
}
template<typename R, typename F> auto rtCaller2(R r, F f) -> typename R::type {
return f();
}
template<typename F> void rtCaller(F f) {
auto a = rtCaller2(ReturnTypeCapture::ret_type<F>{}, f);
std::cout << a << " (type: " << typeid(a).name() << ")" << std::endl;
}
// ...
rtCaller(f1); // Output (with gcc): "Nyahaha. (type: Ss)"
rtCaller(f2); // Output (with gcc): "-42 (type: i)"
rtCaller(f3); // Output (with gcc): "& (type: c)"
Furthermore, we can simplify it even more, and check the return type without a separate wrapper.
template<typename F> auto rtCaller2(F f) -> typename ReturnTypeCapture::ret_type<F>::type {
return f();
}
template<typename F> void rtCaller(F f) {
auto a = rtCaller2(f);
std::cout << a << " (type: " << typeid(a).name() << ")" << std::endl;
}
// ...
rtCaller(f1); // Output (with gcc): "Nyahaha. (type: Ss)"
rtCaller(f2); // Output (with gcc): "-42 (type: i)"
rtCaller(f3); // Output (with gcc): "& (type: c)"
// Same output.
Having that sticking off the end there is really ugly, though, so can't we do better than that? The answer is... yes! We can use an alias declaration to make a typedef, leaving a cleaner name. And thus, the final result here is:
namespace ReturnTypeCapture {
// Credit goes to Angew ( https://stackoverflow.com/a/18695701/5386374 )
template<typename T> struct ret_type;
template<typename RT, typename... Ts> struct ret_type<RT (*)(Ts...)> {
using type = RT;
};
} // namespace ReturnTypeCapture
template <typename F> using RChecker = typename ReturnTypeCapture::ret_type<F>::type;
std::string f1() { return std::string("Nyahaha."); }
int f2() { return -42; }
char f3() { return '&'; }
template<typename F> auto rtCaller2(F f) -> RChecker<F> {
return f();
}
template<typename F> void rtCaller(F f) {
auto a = rtCaller2(f);
std::cout << a << " (type: " << typeid(a).name() << ")" << std::endl;
}
So now, if we combine parameter checking & return type deduction...
// Parameter match checking.
namespace ParameterCheck {
template<typename T, typename... Ts> struct parameter_match : public std::false_type {};
// Declare (GetColor, int16_t*) valid.
template<> struct parameter_match<int (*)(int16_t*), int16_t*> : public std::true_type {};
// Declare (GetFile, FilePath&) valid.
template<> struct parameter_match<int (*)(FilePath&), FilePath> : public std::true_type {};
// Declare (WriteDocument, const FilePath&, const char*, bool) valid.
template<> struct parameter_match<int (*)(const FilePath&, const char*, bool), FilePath, const char*, bool> : public std::true_type {};
// Declare everything without a parameter list valid.
template<typename T> struct parameter_match<T (*)()> : public std::true_type { };
} // namespace ParameterCheck
// Discount return type deduction:
namespace ReturnTypeCapture {
// Credit goes to Angew ( https://stackoverflow.com/a/18695701/5386374 )
template<typename T> struct ret_type;
template<typename RT, typename... Ts> struct ret_type<RT (*)(Ts...)> {
using type = RT;
};
} // namespace ReturnTypeCapture
// Alias declarations:
template<typename F, typename... Ts> using PChecker = ParameterCheck::parameter_match<F, Ts...>;
template<typename F> using RChecker = typename ReturnTypeCapture::ret_type<F>::type;
// ---------------
int GetColor(int16_t* color);
int GetFile(FilePath& file);
int WriteDocument(const FilePath& file, const char* fileFormatName, bool askForParams);
std::string f1() { return std::string("Nyahaha."); }
int f2() { return -42; }
char f3() { return '&'; }
// ---------------
// Calling function (C++11):
// The actual calling function.
template<typename Func, typename... Ts> auto caller2(std::true_type x, Func f, Ts... args) -> RChecker<Func> {
std::cout << "Now calling... ";
return f(args...);
}
// Parameter mismatch overload.
template<typename Func, typename... Ts> auto caller2(std::false_type x, Func f, Ts... args) -> RChecker<Func> {
std::cout << "Parameter list mismatch." << std::endl;
return static_cast<RChecker<Func> >(0); // Just to make sure we don't break stuff.
}
// Wrapper to check for parameter mismatch.
template<typename Func, typename... Ts> auto caller(Func f, Ts... args) -> RChecker<Func> {
// return caller2(ParameterCheck::parameter_match<Func, Ts...>{}, f, args...);
return caller2(PChecker<Func, Ts...>{}, f, args...);
}
// ---------------
// Calling function (C++14):
// The actual calling function.
template<typename Func, typename... Ts> auto caller2(std::true_type x, Func f, Ts... args) {
std::cout << "Now calling... ";
return f(args...);
}
// Parameter mismatch overload.
template<typename Func, typename... Ts> auto caller2(std::false_type x, Func f, Ts... args) {
std::cout << "Parameter list mismatch." << std::endl;
}
// Wrapper to check for parameter mismatch.
template<typename Func, typename... Ts> auto caller(Func f, Ts... args) {
// return caller2(ParameterCheck::parameter_match<Func, Ts...>{}, f, args...);
return caller2(PChecker<Func, Ts...>{}, f, args...);
}
You should be able to get the functionality you want out of this, I believe. The only caveat is that if you do it this way, you need to explicitly declare functions valid in ParameterCheck, by making a template specialisation for the function & its parameter list, derived from std::true_type instead of std::false_type. I'm not sure if there's a way to get true dynamic parameter list checking, but it's a start.
[I'm not sure if you can just overload caller() or if you explicitly need to use caller2() as well. All my attempts to overload caller() via template parameters ended up crashing the compiler; for some reason, it chose template<typename Func, typename... Ts> void caller(Func f, Ts... args) as a better match for caller(std::true_type, f, args...) than template<typename Func, typename... Ts> caller(std::true_type x, Func f, Ts... args), even with the latter listed before the former, and tried to recursively expand it until it ran out of memory. (Tested on two online gcc compilers: Ideone, and TutorialsPoint's compiler (with -std=c++11). I'm not sure if this is a gcc problem, or if I was a bit off about how template matching works. Unfortunately, the online VStudio compiler is down for maintenance, and the only version of VS I have available to me offline at the moment doesn't support variadic templates, so I can't check which is the case.) Unless someone says otherwise, or says how to fix that particular issue, it's probably best to just use caller() as a wrapper & caller2() to do the heavy lifting.]
Examples of pretty much everything here that would be relevant to your problem: here
Also, note that you can't easily pull individual arguments from a parameter pack. You can use recursion to strip arguments off the front a few at a time, you can use them to initialise member variables in a constructor's initialisation list, you can check how many arguments are in the pack, you can specialise it (as we did for parameter_match), & you can pass the whole pack to a function that takes the right number of arguments, but I believe that's it at the moment. This can make them a bit more awkward than C-style varargs at times, despite being more efficient. However, if your ExecuteMethod()'s argument list consists of a function and its argument list, and nothing else, this isn't an issue. As long as the parameter match succeeds, we can just give the entire pack to the passed function, no questions asked. On that note, we can rewrite ExecuteMethod() into something like...
// Not sure what cx is, leaving it alone.
// Assuming you wanted ExecuteMethod to take parameters in the order (cx, function, function_parameter_list)...
// Parameter list match.
template<typename M, typename... Parameters>
static bool ExecuteMethodWorker(std::true_type x, JSContext* cx, M method, Parameters... params)
{
auto r = method(params...);
// ...
}
// Parameter list mismatch.
template<typename M, typename... Parameters>
static bool ExecuteMethodWorker(std::false_type x, JSContext* cx, M method, Parameters... params)
{
// Handle parameter type mismatch here.
// Omit if not necessary, though it's likely better to use it to log errors, terminate, throw an exception, or something.
}
// Caller.
template<typename M, typename... Parameters>
static bool ExecuteMethod(JSContext* cx, M method, Parameters... params)
{
return ExecuteMethodWorker(PChecker<M, Parameters...>{}, cx, method, params...);
}
Make sure to either prototype or define the worker functions before ExecuteMethod(), so the compiler can resolve the call properly.
(Apologies for any typoes I may have missed anywhere in there, I'm a bit tired.)
Edit: I've located the problem with passing references to a template. It seems that using templates to determine types does indeed remove reference-ness in and of itself, hence notation like template<typename T> void func(T&) for functions that take a reference. Sadly, I'm not yet sure how to fix this issue. I did, however, come up with a new version of PChecker that dynamically reflects types for any function that doesn't use reference types. So far, however, you still need to add references manually, and non-const references probably won't work properly for now.
namespace ParameterCheck {
namespace ParamGetter {
// Based on an answer from GManNickG ( https://stackoverflow.com/a/4693493/5386374 )
// Turn the type list into a single type we can use with std::is_same.
template<typename... Ts> struct variadic_typedef { };
// Generic case, to catch passed parameter types list.
template<typename... Ts> struct variadic_wrapper {
using type = variadic_typedef<Ts...>;
};
// Special case to catch void parameter types list.
template<> struct variadic_wrapper<> {
using type = variadic_typedef<void>;
};
// Generic case to isolate parameter list from function signature.
template<typename RT, typename... Ts> struct variadic_wrapper<RT (*)(Ts...)> {
using type = variadic_typedef<Ts...>;
};
// Special case to isolate void parameter from function signature.
template<typename RT> struct variadic_wrapper<RT (*)()> {
using type = variadic_typedef<void>;
};
} // namespace ParamGetter
template<typename... Ts> using PGetter = typename ParamGetter::variadic_wrapper<Ts...>::type;
// Declare class template.
template<typename... Ts> struct parameter_match;
// Actual class. Becomes either std::true_type or std::false_type.
template<typename F, typename... Ts> struct parameter_match<F, Ts...> : public std::integral_constant<bool, std::is_same<PGetter<F>, PGetter<Ts...> >{}> {};
// Put specialisations for functions with const references here.
} // namespace ParameterCheck
template<typename F, typename... Ts> using PChecker = ParameterCheck::parameter_match<F, Ts...>;
See here.
--
Edit 2: Okay, can't figure out how to grab the passed function's parameter list and use it directly. It might be possible using tuples, perhaps using the rest of GManNickG's code (the convert_in_tuple struct), but I haven't looked into them, and don't really know how to grab the entire type list from a tuple at the same time, or if it's even possible. [If anyone else knows how to fix the reference problem, feel free to comment.]
If you're only using references to minimise passing overhead, and not to actually change data, you should be fine. If your code uses reference parameters to modify the data that the parameter is pointing to, however, I'm not sure how to help you. Sorry.
--
Edit 3: It looks like RChecker might not be as necessary for C++11 function forwarding, we can apparently use decltype([function call]) for that. So...
// caller2(), using decltype. Valid, as args... is a valid parameter list for f.
template<typename Func, typename... Ts> auto caller2(std::true_type x, Func f, Ts... args) -> decltype(f(args...)) {
std::cout << "Now calling... ";
return f(args...);
}
// Parameter mismatch overload.
// decltype(f(args...)) would be problematic, since args... isn't a valid parameter list for f.
template<typename Func, typename... Ts> auto caller2(std::false_type x, Func f, Ts... args) -> RChecker<Func> {
std::cout << "Parameter list mismatch." << std::endl;
return static_cast<RChecker<Func> >(0); // Make sure we don't break stuff.
}
// Wrapper to check for parameter mismatch.
// decltype(caller2(PChecker<Func, Ts...>{}, f, args...)) is valid, but would be more verbose than RChecker<Func>.
template<typename Func, typename... Ts> auto caller(Func f, Ts... args) -> RChecker<Func> {
// return caller2(ParameterCheck::parameter_match<Func, Ts...>{}, f, args...);
return caller2(PChecker<Func, Ts...>{}, f, args...);
}
However, as noted, decltype can have issues when it can't find a function call that matches what it's passed exactly. So, for any case where the parameter mismatch version of caller2() is called, trying to use decltype(f(args...)) to determine return type would likely cause issues. However, I'm not sure if decltype(auto), introduced in C++14, would have that issue.
Also, in C++14-compatible compilers, it's apparently better to use decltype(auto) than just auto for automatic return type determination; auto doesn't preserve const-ness, volatile-ness, or reference-ness, while decltype(auto) does. It can be used either as a trailing return type, or as a normal return type.
// caller2(), using decltype(auto).
template<typename Func, typename... Ts> decltype(auto) caller2(std::true_type x, Func f, Ts... args) {
std::cout << "Now calling... ";
return f(args...);
}
decltype(auto) can also be used when declaring variables. See here for more information.
Edit 4: I believe I may have found a potential solution that preserves the passed function's parameter list properly, using functors. However, it may or may not create unwanted overhead, I'm not sure.
// Default functor.
template<typename... Ts>
struct Executor { };
// General case.
template<typename M, typename ReturnType, typename... Params>
struct Executor<M, ReturnType (*)(Params...)> {
public:
// Parameter match:
bool operator()(M method, Params... params) {
ReturnType r = method(params...);
// ...
}
// Parameter mismatch:
template<typename... Invalid_Params>
bool operator()(M method, Invalid_Params... ts) {
// Handle parameter type mismatch here.
}
};
// Special case to catch void return type.
template<typename M, typename... Params>
struct Executor<M, void (*)(Params...)> {
public:
// Parameter match:
bool operator()(M method, Params... params) {
method(params...);
// ...
}
// Parameter mismatch:
template<typename... Invalid_Params>
bool operator()(M method, Invalid_Params... ts) {
// Handle parameter type mismatch here.
}
};
// Variadic function-like macro to automatically create, use, and destroy functor.
// Uncomment whichever one is appropriate for the compiler used.
// (The difference being that Visual C++ automatically removes the trailing comma if the
// macro has zero variadic arguments, while GCC needs a hint in the form of "##" to tell
// it to do so.)
// Also note that the "do { ... } while (false)" structure is used to swallow the trailing
// semicolon, so it doesn't inadvertently break anything; most compilers will optimise it
// out, leaving just the code inside.
// (Source: https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html )
// MSVC:
// #define ExecuteMethod(C, M, ...) \
// do { \
// Executor<decltype(&M), decltype(&M)> temp; \
// C = temp(M, __VA_ARGS__); \
// } while (false)
// GCC:
#define ExecuteMethod(C, M, ...) \
do { \
Executor<decltype(&M), decltype(&M)> temp; \
C = temp(M, ##__VA_ARGS__); \
} while (false)
In this case, you can use it as:
ExecuteMethod(return_value_holder, function_name, function_parameter_list);
Which expands to...
do {
Executor<decltype(&function_name), decltype(&function_name)> temp;
return_value_holder = temp(function_name, function_parameter_list);
} while (false);
With this, there's no need to manually go through the parameter pack and make sure each one matches the passed function's parameters. As the passed function's parameter list is quite literally built into Executor as Params..., we can simply overload the function call operator based on whether the arguments it was passed match Params... or not. If the parameters match the function, it calls the Parmas... overload; if they don't, it calls the Invalid_Params... overload. A bit more awkward than true reflection, IMO, but it seems to match everything properly.
Note that:
I'm not sure whether using functors liberally can cause any performance or memory use overhead. I'm... not all that familiar with them at the moment.
I don't know if it's possible to combine the general case and the "void return type" special case into a single functor. The compiler complained when I tried, but I'm not sure if it's because it isn't possible or because I was doing it wrong.
Considering #2, when modifying this version of ExecuteMethod()'s parameters, you have to modify it and both versions of Executor to match.
Like so, where JSContext* cx is added to the parameter list:
template<typename M, typename ReturnType, typename... Params>
struct Executor<M, ReturnType (*)(Params...)> {
public:
bool operator()(JSContext* cx, M method, Params... params);
};
template<typename M, typename... Params>
struct Executor<M, void (*)(Params...)> {
public:
bool operator()(JSContext* cx, M method, Params... params);
};
#define ExecuteMethod(C, cx, M, ...) \
do { \
Executor<decltype(&M), decltype(&M)> temp; \
C = temp(cx, M, ##__VA_ARGS__); \
} while (false)
This may be the solution, but it requires further testing to see if it has any negative impacts on performance. At the very least, it'll make sure const-ness and reference-ness is preserved by ExecuteMethod(), and it's a lot cleaner than my old ideas.
See here.
There are further improvements that can be made, however. As I'm out of space, see here.
Notes:
int16_t (a.k.a. std::int16_t) is in the header <cstdint>.
std::true_type and std::false_type are in the header <type_traits>.
It's difficult to tell from your description, but this is my closest interpretation to what you asked:
auto foo(int) { cout << "foo int" << endl; }
auto foo(float) { cout << "foo float" << endl; }
//... other foo overloads...
template <class T>
auto uber_function(T t)
{
foo(t);
}
template <class T, class... Args>
auto uber_function(T t, Args... args)
{
foo(t);
uber_function(args...);
}
auto main() -> int
{
uber_function(3, 2.4f);
return 0;
}
Of course this can be improved to take references, to make forwarding. This is just for you to have a starting point. As you weren't more clear, I can't give a more specific answer.

Distribute argument parameter pack to invoke two functors

I'm trying to invoke two functional objects through one given argument pack (typename Args... args), an integer parameter is provided to mark the border where i need to split the pack to invoke both functional objects correctly.
Consider the following example:
Args... = <int, int, std::vector<int>, std::vector<int>>
unsigned Bounds = 2;
functor Foo (left) and Bar (right)
// Foo is invoked with <int, int>
// Bar is invoked with <std::vector<int>, std::vector<int>>
// An evaluator template class is invoked to merge the result of both,
// for example with an add (operator+) operation
My idea was to create two integer sequences and use std::get to invoke both functional objects at once with those two integer sequences:
// Sequence creator
template<unsigned Position, unsigned Count, unsigned... Pack>
struct make_sequence
: std::conditional<
Count == 0,
std::common_type<sequence<Pack...>>,
make_sequence<Position + 1, Count - 1, Pack..., Position>
>::type { };
// Create a sequence from inclusive from to exclusive to
template<unsigned InclusiveFrom, unsigned ExclusiveTo>
using make_sequence_from_to_t = typename make_sequence<
InclusiveFrom,
(ExclusiveTo <= InclusiveFrom) ? 0U : (ExclusiveTo - InclusiveFrom)
>::type;
template<typename LeftType, typename RightType, unsigned Bounds, typename Evaluator>
class distribute_functor
{
LeftType left_;
RightType right_;
template<unsigned... LeftSeq, unsigned... RightSeq, typename... Args>
auto internal_invoke(sequence<LeftSeq...>, sequence<RightSeq...>, Args... args)
{
return Evaluator::evaluate(left_(std::get<LeftSeq>(args)...),
// ~~~~~~~~~~~~~~~^^^^^^^~~^^^^~~~~~
// error C3528: 'LeftSeq': the number of
// elements in this pack expansion does not
// match the number of elements in 'args'
right_(std::get<RightSeq>(args)...));
}
public:
template<typename Left, typename Right>
distribute_functor(Left left, Right right)
: left_(std::forward<Left>(left)), right_(std::forward<Right>(right)) { }
template<typename... Args>
auto operator() (Args... args)
{
return internal_invoke(make_sequence_from_to_t<0, Bounds>{},
make_sequence_from_to_t<Bounds, sizeof...(Args)>{},
std::forward<Args>(args)...);
}
};
However the VisualStudio 14 compiler complains about a mismatch between the count of parameters in the arguments pack and in the sequence:
error C3528: 'LeftSeq': the number of elements in this pack expansion does not match the number of elements in 'args'
There is still the way to use std::tuple for the functor invocation which i don't prefer.
Is there another or better way to partial invoke two functional objects in one step from one argument pack?
std::get cannot be used this way.
You should write internal_invoke like this:
template<unsigned... LeftSeq, unsigned... RightSeq, typename ArgsAsTuple>
auto internal_invoke(sequence<LeftSeq...>, sequence<RightSeq...>,ArgsAsTuple&& args) const
{
return Evaluator::evaluate(left_(std::get<LeftSeq>(args)...),
right_(std::get<RightSeq>(args)...));
}
And invoke it with forward_as_tuple:
return internal_invoke(make_sequence_from_to_t<0, Bounds>{},
make_sequence_from_to_t<Bounds, sizeof...(Args)>{},
std::forward_as_tuple(args...));
Explanation:
Two paramter packs of different arity must be expanded separately. When you write std::get<LeftSeq>(args)..., you try to expand together packs of different arity. This cannot be done. You should have wrote std::get<LeftSeq>(args... /* 1st expand/) ... /* 2nd expand */. This is syntactically correct but does not match std::get API. std::forward_as_tuple is there to help you and has been written precisely for those types of use cases.
Edit:
If you want to avoid the tuple, then you must write your own version of std::get to match your need, provided you expand the parameters correctly as I explained above.