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

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");

Related

Overloading between printf functions and fmt functions

I have a class that takes a C printf set of variadic arguments in its constructor, like this:
class Foo {
public:
Foo(const char* str, ...) __attribute__((format(printf, 2, 3)));
Now I want to be able to use the fmt library with this class. If I were willing to change all callers I could switch it something like this:
class Foo {
public:
template<typename Str, typename... Args>
Foo(const Str& str, const Args&... args)
: Foo(str, fmt::make_args_checked<Args...>(str, args...))
{}
private:
Foo(fmt::string_view fmt, fmt::format_args args);
But this class is used in 100's of places and it's not feasible to "change the world". So I want to keep both constructors, but obviously now I need a way to choose between them. I'm not excited about having to add a new dummy parameter or something.
Then I thought, well, I'd also really like to enforce using the FMT_STRING() macro since my printf-style code takes advantage of printf format checking in GCC and clang. So maybe I could do something with that: I could create my own macro, say MYFMT(), that would invoke FMT_STRING() somehow, or at least do the same checking, but then resolve to my own type that could be used to choose a different constructor; something like:
#define MYFMT(_f) ...
class Foo {
public:
Foo(const char* str, ...);
Foo(const MyType& str, ...) ...
So, the usage would be something like:
auto x = Foo("this is a %s string", "printf");
auto y = Foo(MYFMT("this is a {} string"), "fmt");
But I have played with this for a few hours and tried to wrap my head around how the FMT_STRING macro works and what I'd need to do, and I can't come up with anything. Maybe this isn't possible for some reason but if anyone has any hints that would be great.
FWIW my base compilers are GCC 10, clang 9, and MSVC 2019 so I can rely on C++17 at least.
You can do it as follows (godbolt):
#include <fmt/core.h>
struct format_string {
fmt::string_view str;
constexpr operator fmt::string_view() const { return str; }
};
#define MYFMT(s) format_string{s}
class Foo {
public:
template <typename... T>
Foo(const char* str, T&&... args) {
fmt::print("printf\n");
}
template <typename... T>
Foo(fmt::format_string<T...> str, T&&... args) {
fmt::print("fmt\n");
}
};
int main() {
Foo("%d\n", 42); // calls the printf overload
Foo(MYFMT("{}\n"), 42); // calls the fmt overload
}
With C++20 this will give you compile-time checks in {fmt}. Note that varargs are replaced with variadic templates in the printf overload to avoid ambiguity so you won't be able to apply the format attribute. It might be possible to keep varargs by tweaking this solution a bit.
A better option would be to avoid overloading and macros altogether and use a different function instead:
class Foo {
private:
Foo() {}
public:
Foo(const char* str, ...) {
fmt::print("printf\n");
}
template <typename... T>
static Foo format(fmt::format_string<T...> str, T&&... args) {
fmt::print("fmt\n");
return Foo();
}
};

C++ - vsprintf_s and std::string?

I have a logging function that uses '...' parameters and creates the final output string with vsprintf_s
it works fine except that I always have to use c_str() to print strings
at first I thought it was not a problem, but it's a pain to add all these .c_str() after each string variables, while I keep forgetting them
I though maybe a C++ guru could enlight me on this issue, is there a way to have my logging function take care of this by itself ?
void Logger::print(const std::string fmt, ...)
{
va_list args;
int len;
char * buffer;
va_start(args, fmt);
len = _vscprintf(fmt.c_str(), args)+1;
buffer = (char*)malloc(len * sizeof(char));
vsprintf_s(buffer, len, fmt.c_str(), args);
va_end(args);
std::cout << buffer << std::endl;
free(buffer);
}
thanks
You can add two variadic wrapper function templates like this:
#include <type_traits>
template <class Arg>
decltype(auto) prepare(const Arg& arg)
{
if constexpr (std::is_same_v<Arg, std::string>)
return arg.c_str();
else
return arg;
}
template <class ...Args>
void printWrapper(Args&&... args)
{
Log::print(prepare(std::forward<Args>(args))...);
}
and invoke printWrapper instead of the original member function. Note that I assumed Log::print to be static member function here. If that't not the case, you need adjust it. This should work now:
const std::string hello("hello");
printWrapper("%d %s %s", 42, hello, "world");
Note that C++17 is required for this to compile.

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!

keep complete type of a function pointers parameters in template deduction

I'm trying to get a way to keep the complete type of a function pointer's parameters when passed into a template function.
This is an example of what I'd like to do:
#include <stdio.h>
#include <utility>
template<typename _Ret, typename... Args>
static _Ret call(_Ret (*fp)(Args&&...), Args &&... args)
{
return fp(std::forward<Args>(args)...);
}
int foo(int arr[4])
{
printf("arr: %i,%i,%i,%i\n", arr[0], arr[1], arr[2], arr[3]);
return 0;
}
int main(int, char**)
{
int arr[4] = { 1, 2, 3, 4 };
int (*foo_ptr)(int arr[4]) = &foo;
call<int>(foo_ptr, arr);
return 0;
}
Unfortunately the type that call actually sees foo_ptr as int (*)(int*) rather than int (*)(int [4]) or int (*)(int (&)[4]).
The reason for the rvalue references is that is the only way to keep the array's type at all, but it doesn't seem to work for function pointer parameters.
As to why I want to do this, I have a nearly magical lua binding lib that is 100% template based, and requires no code to link to. In order for it to be able to support binding to properties and variables that are arrays themselves the rvalue references are required. int* and int (&)[4] are not compatible types.
The idea is to allow binding existing apis, even C apis as transparently and automagically as possible, while doing as much of the type checking at compile time as is possible.
Is this possible at all?
Edit:
Ok, my example was probably a bit too simplified. I can't actually change the definition of the functions that get passed into "call", as this library is meant to allow binding to any random function a user might want.
here for example is my static function (non method) binding method:
template<typename _Ret, typename... _Args>
LuaGlue &func(const std::string &name, _Ret (*fn)(_Args...))
{
auto new_func = new LuaGlueFunction<_Ret, _Args...>(this, name, fn);
functions.addSymbol(name.c_str(), new_func);
return *this;
}
And LuaGlueFunction happens to look like this:
template<typename _Ret, typename... _Args>
class LuaGlueFunction : public LuaGlueFunctionBase
{
public:
typedef _Ret ReturnType;
typedef _Ret (*MethodType)( _Args... );
LuaGlueFunction(LuaGlueBase *lg, const std::string &n, MethodType fn) :
g(lg), name_(n), fn_(std::forward<decltype(fn)>(fn))
{ }
~LuaGlueFunction() {}
std::string name() { return name_; }
bool glue(LuaGlueBase *luaGlue)
{
lua_pushlightuserdata(luaGlue->state(), this);
lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
//printf("add function: %s\n", name_.c_str());
lua_setglobal(luaGlue->state(), name_.c_str());
return true;
}
int invoke(lua_State *state)
{
ReturnType ret = applyTuple(g, state, fn_, args);
lua_pop(state, Arg_Count_);
stack<_Ret>::put(g, state, ret);
return 1;
}
private:
LuaGlueBase *g;
std::string name_;
MethodType fn_;
std::tuple<_Args...> args;
static const unsigned int Arg_Count_ = sizeof...(_Args);
static int lua_call_func(lua_State *state)
{
auto mimp = (LuaGlueFunction<_Ret, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
return mimp->invoke(state);
}
};
I'm attempting to allow the detection of an array, and then autobox it in a LuaGlueStaticArray type internally (that part already works, assuming I can keep the array from decaying into a pointer).
Hopefully that helps explain a little better what I'm trying to do.
There's a problem with the call function template. It needs to be defined as
template<typename _Ret, typename... Args>
static _Ret call(_Ret (*fp)(Args...), Args &&... args)
// ^^^ no &&
You want perfect forwarding for the arguments you pass in, but you do no want to force the types of the function parameters to reference types.
Next, when you pass an array to a function it decays to a pointer to the address of the first element. So your function foo is actually equivalent to
int foo(int *arr) // size information is lost
Keeping this in mind, you do not want arr to be deduced as int (&)[4] when you pass it to call, so you must pass a pointer.
call<int>(foo_ptr, &arr[0]); // pass a pointer to the beginning
After making these changes your code works. Live demo
If you want to preserve the array's size when passing it to foo, change that function to
int foo(int (&arr)[4])
{ ... }
And then call it as
decltype(foo)* foo_ptr = &foo;
call<int>(foo_ptr, arr);
As mpark points out in the comments, in both examples above there's no need to explicitly mention the return type of call, or form the function pointer foo_ptr. The calls can simply be
call(foo, &arr[0]); // with int foo(int *arr)
or
call(foo, arr); // with int foo(int (&arr)[4])
Live demo

To invoke a variadic function with unamed arguments of another variadic function

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.