I'm calling APIs in a specific way with the help of templates and I have left one problem with passing a constant parameter.
My try with int bound:
template <typename F, typename ...Ts>
static int f3(int bound, CString file, int line, CString Caller,
CString f_name, F f, Ts&& ...ts) {
int err = fn(bound, file, line, Caller, f_name,
f, std::tuple<Ts...>(ts...), seq3<bound>{}, // error C2975
seq1<sizeof...(Ts)>{});
return err;
}
In main:
int const bound;
bound = 4;
err = fn(bound, api(GetModuleFileName), rval, nullptr, path, MAX_PATH, L"EXE-path");
compiler error C2975: 'N': invalid template argument for 'seq3', expected compile-time constant expression
How to fix this?
My workaround by now:
err = f3(api(GetModuleFileName), rval, nullptr, path, MAX_PATH, L"EXE-path");
f3 is a specialisation for an API with 3 arguments, because I'm up to now not able to pass in the upper bound - 4 in this case - for generating a sequence: <1,2,3>. This sequence is needed to call an API with 3 arguments, where the tupel starts at the parameter rval in f3().
Background:
api is a #define
f3 calls the API.
f3 handles the return value of the API at the 0 position of the sequence/tupel.
f3 calls with all parameters another variadic function for logging debug informations.
One tupel and two sequences for two function calls.
PROBLEM:
I want to pass a parameter to control the upper bound of a sequence not given by the tupel-size but by the API function signature.
I want only one fn() for all APIs and not f0(), f1(), f2(), f3() ..... for APIs with 0, 1, 2, 3 ... arguments.
I want something like this:
err = fn(seq3<4>, api(GetModuleFileName), rval, nullptr, path, MAX_PATH, L"EXE-path")
Here's my working code:
#include <windows.h>
#include <atlstr.h>
#include <tuple>
#include <utility>
template <int ... Ns> struct seq_3 {};
template <int ... Ns> struct seq3_n {};
template <int I, int ... Ns> struct seq3_n<I, Ns...>{
using type = typename seq3_n<I - 1, I - 1, Ns...>::type;};
template <int ... Ns> struct seq3_n<1, Ns...>{
// skip first argument : rval, because it doesn't fit to API,
// but needed for calling other function
using type = seq_3<Ns...>; };
template <int N>
using seq3 = typename seq3_n<N>::type;
template <int ... Ms> struct seq_1 {};
template <int ... Ms> struct seq1_n {};
template <int J, int ... Ms> struct seq1_n<J, Ms...>{
using type = typename seq1_n<J - 1, J - 1, Ms...>::type; };
template <int ... Ms> struct seq1_n<0, Ms...> {
using type = seq_1<Ms...>; };
template <int M>
using seq1 = typename seq1_n<M>::type;
template <typename F, typename TUP, int ... INDICES3, int ... INDICES1>
static int fn(CString file, int line, CString Caller, CString f_name,
F f, TUP tup, seq_3<INDICES3...>, seq_1<INDICES1...>) {
int err = 0;
// handling of rval = first element of tuple
std::get<0>(tup) = f(std::get<INDICES3>(tup) ...); // calling API
err = GetLastError();
/* calling next function (variadic too) with same tupel, but other sequence
myOpenDebugOutputString(project, file, line, Caller, f_name, std::get<INDICES1>(tup) ..., "stop");
*/
return err; }
template <typename F, typename ...Ts>
static int f3(CString file, int line, CString Caller, CString f_name,
F f, Ts&& ...ts) {
int err = fn(file, line, Caller, f_name,
f, std::tuple<Ts...>(ts...), seq3<4>{}, // sequence fixed by f3
seq1<sizeof...(Ts)>{}); // 3 arguments api + skip 1 rval = 4
return err; // given by signature of API
}
int main() {
// for calling simple API GetModulFileName with 3 arguments
// returns len(path)
wchar_t path[MAX_PATH];
DWORD rval = 0;
int err = 0;
rval = GetModuleFileName( nullptr, path, MAX_PATH);
err = GetLastError();
#define api(a) __FILE__, __LINE__, __func__, L#a, a
// L#a becomes L"GetModuleFileName"
err = f3(api(GetModuleFileName), rval, nullptr, path, MAX_PATH, L"EXE-path");
return 0; }
Thanks in advance.
P.S. I'm using Microsoft Visual Studio 2015
Update:
I tried following in template api_call from Richard Hodges solution.
std::tuple<GivenArgs...> tup(args...);
// OK, but only for an api with 3 arguments
callsite.function(std::get<0>(tup), std::get<1>(tup), std::get<2>(tup));
// compiler error too many arguments
callsite.function(std::forward<GivenArgs>(args)..., seq1<callsite.nofArgs()>{});
// compiler error too few arguments
callsite.function(tup, seq1<callsite.nofArgs()>{});
Remarks:
seq1<3> = seq_1<0,1,2>
callsite.nofArg() = 3
How to get the correct number of arguments?