To invoke a variadic function with unamed arguments of another variadic function - c++

I have two variadic function as foo(format, ...) and bar(format, ...). I want to implement function foo so that it can invoke bar with the same list of arguments it has. That is,
foo(format...)
{
...
bar(format, ...);
}
For instance, invoking foo("(ii)", 1, 2) will invoke bar with same arguments bar("(ii)", 1, 2). How should this foo function be implemented?
PS: function bar is from a legacy library which I cant change its interface.

Can't be done, as long as all you have is a bunch if functions with ... arguments.
You have to plan ahead for things like that and implement each variadic fuinction in two-staged fashion
void vfoo(format, va_list *args) {
/* Process `*args` */
}
void foo(format, ...) {
va_list args;
va_start(args, format);
vfoo(format, &args);
va_end(args);
}
Once you have each of your variadic functions implemented through a pair of va_list * function and ... function, you can delegate the calls using the va_list * versions of the functions
void vfoo(format, va_list *args) {
...
vbar(format, args);
...
}

GCC can construct function calls at runtime.
foo() {
void *args = __builtin_apply_args();
void *ret = __builtin_apply(bar, args, ???);
__builtin_return(ret);
}
??? is the amount of stack space the arguments take up, which is not necessarily trivial to compute: you will need to understand what the arguments are and architecture-specific details on how they are passed.
Other GCC extensions allow further trickery with macros and inline functions.

Short answer - you cannot. Make bar take a va_list. If you're willing to lock this down to one specific compiler, you could probably do it with inline assembly, but with standard C or C++ it's not possible.
You should, as a general rule, always implement your vararg functions in terms of va_list and then make a wrapper ellipsis function calling the real va_list function.

This works in C++:
#include <iostream>
template<typename Format>
void meheer(const Format& format) {
std::cout << format << std::endl;;
}
template<typename Format, typename Elt, typename ... Args>
void meheer(const Format& format, const Elt & e, const Args&... args) {
std::cout << format << e;
meheer(format, args...);
}
template<typename Format, typename ... Args>
void ohai(const Format& format, const Args&... args) {
meheer(format, args...);
}
int main(int argc, char ** argv) {
ohai(1,2,3);
return EXIT_SUCCESS;
}
Output:
12131
Of course, this is C++0x specific, but it works in my not-super-recent version of gcc. See also: http://en.wikipedia.org/wiki/C%2B%2B0x#Variadic_templates
Update Added full-length example.

Related

Is it possible to pass variadic template parameters to va_list?

A mirroring question of Is it possible to pass va list to variadic template
In my project for testing, there is a function:
void Func(LPCSTR format, ...) {
va_list args;
va_start(args, format);
char buffer[256];
vsprintf_s(buffer, 256, format, args);
printf("%s\n", buffer);
va_end(args);
}
And I write a template function:
template<typename... Args>
void FuncTemp(LPCSTR format, Args... args) {
Func(format, args...); //#1
}
Is the call for Func in line #1 right? I have tested my program, and it seemed to produce the correct results. Are there problems or pitfalls writing like this way?
The logic behind this:
I want to realize a log writing class which can decide to write logs to local positions or submitte to servers:
Class LogWriting{
public:
...
LogTypes mLogType;
void WriteLogs(...){
switch (mlogType) {
case(LogTypes::local): {
// need to call <void LogLocal(LPCSTR format, ...)> here
// which CANNOT be changed.
break;
}
case(LogTypes::online): {
// need to call
/* template<typename... Args>
void LogOnline(LPCSTR format, Args... args)
{
std::string strFormat = std::string(format);
std::string logMessage = fmt::sprintf(strFormat, args...);
reportLog(logMessage);
}
*/
// which CANNOT be changed.
break;
}
...
}
};
Because I cannot change the parameters' types of LogLocal() and LogOnline()(one is va_list and another is variadic template), I decided to set WriteLogs() as a variadic function template to suit these two functions:
template<typename... Args>
void WriteLogs(LPCSTR format, Args... args)

Is there any way to rest set/array to method parameters?

Currently I have a function:
void translate(std::string key, std::string& result, ...)
{
char buffer[1024];
va_list args;
va_start(args, result);
vsnprintf (buffer, sizeof(buffer), (loadedTranslations.find(key) != loadedTranslations.end() ? loadedTranslations[key] : "unknown").c_str(), args);
va_end(args);
result = buffer;
}
I'm getting some data in AMX plugin and I need to pass them into this function. Is there are any way to do this? In JavaScript I can do something like translate(a, b, ...rest) and it will work. Is there some ways to implement same result in C++? The problem is the data isn't one type: there can be integers, floats and strings. So using std::forward (if I correctly understood its use-case) not possible.
Try:
template <typename ... Args>
void translate(std::string key, std::string& result, Args&& ... args)
{
// your code
}
and wherever you need to forward, for eg. to a function foo: foo(std::forward<Args>(args)...)
I'll suggest reading more about variadic template and perfect forwarding.

Pass param packed args into a std::queue to call with a different function later

I asked a similar question earlier without realizing that that wasn't quite specific enough.
So I have this function that has to take in all the arguments of a print function, with the ... and all, and then put it into a queue that will call the actual print function later.
Something like:
std::queue<SOMETHING> queue;
template <typename... Params>
void printLater(int a, int b, char* fmt, Params ...args) {
queue.push(args);
}
template <typename... Params>
void print(int a, int b, char* fmt, Param ...args) {
//whatever
}
void actuallyPrint() {
//whatever
print(queue.pop());
}
Context: I'm working with a piece of hardware that can only handle requests every 50ms or else they're ignored. My goal is to create a wrapper that will automatically add the delays if I send it a bunch at once.
My fallback if I cant do this, although I'd rather do this is just sprintf (or C++ equivalent) into a string only store the string in the queue and call print() without all the args.
Something like this perhaps:
std::queue<std::function<void()>> queue;
template <typename... Params>
void printLater(int a, int b, char* fmt, Params ...args) {
queue.push([=](){ print(a, b, fmt, args...); } );
}
void actuallyPrint() {
queue.front()();
queue.pop();
}

Is it possible to pass va_list to variadic template?

I know that va_list is usually something you should avoid since its not very safe, but is it possible to pass the arguments from a function like:
void foo(...);
to a function like
template<typename... Args>
void bar(Args... arguments);
?
edit: Originally I wanted to try to use this to call a virtual function with a variable amount of arguments / types, but this was not the way to go making this question kind of irrelevant. Eventually I ended up doing something like this:
struct ArgsPackBase
{
virtual ~ArgsPackBase() {}
};
template<typename... Args>
struct ArgsPack : public ArgsPackBase
{
public:
ArgsPack(Args... args_)
: argsTuple(args_...)
{}
void call(std::function<void(Args...)> function)
{
callExpansion(function, std::index_sequence_for<Args...>{});
}
private:
template<std::size_t... I>
void callExpansion(std::function<void(Args...)> function, std::index_sequence<I...>)
{
function(std::get<I>(argsTuple)...);
}
std::tuple<Args...> argsTuple;
};
No, variadic function arguments are a runtime feature, and the number of arguments you pass to a variadic template, although variable, must be known at the compile time.
As observed in RFC1925, "With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea."
As pointed by Piotr Olszewski, the old C-style variadic function arguments is a feature intended to work at run-time; the new variadic template C++-style work at compile time.
So... just for fun... I suppose it can be possible if you know, compile time, the types of the argument for foo().
By example, if foo() is a variadic template function like the foo() in the following example... that compile and work with clang++ but give a compilation error with g++... and I don't know who's right (when I have time, I'll open a question about this)...
#include <cstdarg>
#include <iostream>
#include <stdexcept>
template <typename ... Args>
void bar (Args const & ... args)
{
using unused = int[];
(void)unused { (std::cout << args << ", ", 0)... };
std::cout << std::endl;
}
template <typename ... Ts>
void foo (int num, ...)
{
if ( num != sizeof...(Ts) )
throw std::runtime_error("!");
va_list args;
va_start(args, num);
bar( va_arg(args, Ts)... );
va_end(args);
}
int main ()
{
foo<int, long, long long>(3, 1, 2L, 3LL); // print 1, 2, 3,
}
Observe that you need to pass a reduntant information in foo(): the number of the variadic arguments: the va_start syntax require that you pass a variable (num) with the same value of sizeof...(Ts).
But, I repeat, just for fun.
Why, for goodness sake, we should write a function like foo() when we can directly write a function like bar()?
For C++ template, compiler must produce every instance at compile time. So, for every parameter combination (int,double,float), corresponding instance should appear in object file.
It is not possible for your foo to know every parameter combination, as there are infinite amount - so unless you restrict parameter space somehow, the answer to your question is "no".
However, with some template magic it is possible, but not practically useful. I show one specific example as a proof of concept, but please, do not use this in real code.
Lets say
void foo(const char* s, ...);
expects format string like "ffis", where every character specifies a parameter type (double, double, integer, string in this case). We also have a variadic template bar function which prints its arguments:
template <typename Arg, typename... Args>
void doPrint(std::ostream& out, Arg&& arg, Args&&... args)
{
out << std::forward<Arg>(arg);
using expander = int[];
(void)expander {
0, (void(out << ", " << std::forward<Args>(args)), 0)...
};
out << '\n';
}
void bar() {
std::cout << "no arguments\n";
}
template<typename... Args>
void bar(Args... arguments) {
doPrint(std::cout, arguments...);
}
For foo to work, we will produce at compile time every possible parameter combination up to length N (so, 3^N instances):
//struct required to specialize on N=0 case
template<int N>
struct CallFoo {
template<typename... Args>
static void foo1(const char* fmt, va_list args, Args... arguments) {
if (*fmt) {
using CallFooNext = CallFoo<N - 1>;
switch (*fmt) {
case 'f':
{
double t = va_arg(args, double);
CallFooNext::foo1(fmt + 1, args, arguments..., t);
}break;
case 'i':
{
int t = va_arg(args, int);
CallFooNext::foo1(fmt + 1, args, arguments..., t);
}break;
case 's':
{
const char* t = va_arg(args, const char*);
CallFooNext::foo1(fmt + 1, args, arguments..., t);
}break;
}
} else {
bar(arguments...);
}
}
};
template<>
struct CallFoo<0> {
template<typename... Args>
static void foo1(const char* fmt, va_list args, Args... arguments) {
bar(arguments...);
}
};
void foo(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
//Here we set N = 6
CallFoo<6>::foo1<>(fmt, args);
va_end(args);
}
Main function, for completeness:
int main() {
foo("ffis", 2.3, 3.4, 1, "hello!");
}
Resulting code compiles about 10 seconds with gcc on my machine, but produces the correct string 2.3, 3.4, 1, hello!

Why can't std::function bind to C-style variadic functions?

For example, this fails to compile:
std::function<decltype(printf)> my_printf(printf);
With gcc, the error message reads:
error: variable 'std::function<int(const char*, ...)> my_printf' has initializer but incomplete type
std::function<decltype(printf)> my_printf(printf);
At first I thought this was a bug in gcc, but then I looked at the standard and it looks like this just isn't supported. What's the technical reason for this?
The issue is one of implementation. Let's say it was possible. Then std::function would have to declare (in the case of printf)
int operator()(char* fmt, ...)
When called, it would then have to pass the contents of ... to whatever object you assigned. The issue is that it doesn't know enough about the arguments to know HOW to pass that down, which is an issue. printf() parses the format, but others use other mechanisms (an 'end' value is popular).
For the printf family of functions, I suggest you look at the vXXX versions (e.g. vprintf). Since they use well defined arguments (the last one being the variable argument list), it would be possible to bind std::function to those versions.
Edit:
What you can do, however, is write your own wrapper that uses the vprintf functions, and handles the vararg-> va_list conversion.
#include <cstdio>
#include <cstdarg>
#include <functional>
class PrintWrapper
{
public:
PrintWrapper() = default;
template<typename T>
PrintWrapper( T&& t) : func(std::forward<T>(t))
{
}
int operator()(char const* format, ...)
{
va_list args;
va_start(args, format);
int result = func(format, args);
va_end(args);
return result;
}
private:
std::function< int(char const*, va_list)> func;
};
int main()
{
// Note, you have to use the 'v' versions
PrintWrapper p = std::vprintf;
p("%d %d %s\n", 1,2, "hello");
char buffer[256];
using namespace std::placeholders;
p = std::bind(std::vsnprintf, buffer, sizeof(buffer), _1, _2 );
p("%lf %s\n", 0.1234, "goodbye");
// Since the previous step was a wrapper around snprintf, we need to print
// the buffer it wrote into
printf("%s\n", buffer);
return 0;
}
http://ideone.com/Sc95ch
Write your own template class.
template<typename F>
struct function2
{
F f;
template<typename... Args>
decltype(auto) operator()(Args&&... a)
{
return f(a...);
}
};
function2 a{ printf };
a("%d %u %x %p %s", 1, 1, 1, &a, "test");