Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use variable length parameter list with only one reference parameter?

Tags:

c++

Recently I meet an annoying problem that I want to define functions like this:

std::string my_sprintf(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    ...
}
std::string my_sprintf(const std::string& format, ...)
{
    va_list args;
    va_start(args, format); // error
    ...
}

But it seems reference value can't be the last parameter when using variable length parameter list.

Is that a way that I can let user use std::string as format string?

Maybe factors or something else that detect std::string and convert it as c_str() would work, but I don't know how to deal with the following variable length parameter list.

Edit: I'm not using variadic template because i'm using vsprintf inside. Maybe avoid using vsprintf and using std::stringstream is an option?

like image 884
Jim Yang Avatar asked Jun 06 '16 07:06

Jim Yang


People also ask

How do you pass variable length arguments in Python?

Non - Keyworded Arguments (args) To provide variable-length parameters, we need to use an asterisk before the parameter name in the given method. The type of parameters supplied is a tuple, and within the method, these passed arguments form a tuple with the same name as the parameter, excluding the asterisk.

Can you pass va_list to another function?

The va_list may be passed as an argument to another function, but calling va_arg() within that function causes the va_list to have an indeterminate value in the calling function. As a result, attempting to read variable arguments without reinitializing the va_list can have unexpected behavior.

How do we implement variable sized arguments in generic programming?

A variable-length argument is a feature that allows a function to receive any number of arguments. There are situations where a function handles a variable number of arguments according to requirements, such as: Sum of given numbers. Minimum of given numbers and many more.


2 Answers

The behaviour is undefined: See C++ Standard 18.10/3 (for C++11 and C++14), or cppreference.com: Variadic Arguments.

Essentially you can only use types that are available in C with va_start, although an exception is made for the std::nullptr_t type.

like image 79
Bathsheba Avatar answered Oct 21 '22 23:10

Bathsheba


In C++, the way to pass "unknown" arguments is to use variadic template:

template <typename ... Ts>
std::string my_sprintf(const std::string& format, Ts&&...args)
{
    return my_sprintf(format.c_str(), std::forward<Ts>(args)...);
}

and you version with const char* should probably also be variadic template, by using sprintf instead of vsprintf.

like image 39
Jarod42 Avatar answered Oct 21 '22 22:10

Jarod42