Swift equivalent to #define to get a list of variable arguments

So I have a function in C that works like

#define PRINTF(format) { va_list list; va_start(list, format); vprintf(format, list);}

void foo(const char* format, ...) {
   PRINTF(format)
}

      

I was wondering if I should make the Swift equivalent of the above code, how would I represent ... how? The only ways I know how to use variable arguments is using CVarArgType or using an array of arguments.

However, since this C code snippet uses a macro, I find it difficult to port this code to Swift without changing the parameters of the function I am creating instead of the macro. Can I get an idea of ​​how I would do something like this?

I need help writing a #define macro equivalent function in Swift and I am having trouble getting the va_list equivalent to va_start calls.

+3


source to share


1 answer


Well my original answer absolutely surpassed all things ...

We need to take String

for the format and CVarArgType...

for the argument list (which is treated as [CVarArgType]

inside the function). I complicated this by trying to use Objective-C NSString

. If we're sticking with Swift String

, it actually has an initializer that takes the arguments we pass.

The simplest way to write this function in Swift is as follows:

func foo(format: String, args: CVarArgType...) {
    println(String(format: format, arguments: args))
}

      


As far as I know Swift doesn't support macros #define

. However, we can convert this C macro to a regular Swift function.
func foo(format: String, args: CVarArgType...) {
    println(NSString(format: format, arguments: getVaList(args)))
}

      

CVarArgType

is a Swift protocol that accepts types that we would normally pass to Strings for formatting.

...

causes the function to take any number of arguments for these last parameters. Inside the function, this will be of type [CVarArgType]

(array).

Meanwhile, the initializer NSString

(and similarly, NSLog

and other similar dots) are looked CVaListPointer

for as the last argument, so we can use Swift's built-in function getVaList

, which converts [CVarArgType]

to a CVaListPointer

.



This function can be called as such:

foo("%@, %@... %i", "hello", "world", 123)

      

What will print:

hello, world... 123

      

And as @AirspeedVelocity points out, it is generally recommended to use withVaList

rather than getVaList

. We can do something like this:

func foo(format: String, args: CVarArgType...) {
    func buildLogString(argList: CVaListPointer) -> String {
        return NSString(format: format, arguments: argList) as String
    }
    println(withVaList(args, buildLogString))
}

      


For applications outside the scope of this particular example, it is important to note that we can use ...

any type of argument list to accept, and within this function we get an array of that type.

For example:

func bar(myVariadicListOfStuff: MyStuffClass...) {
    // myVariadicListOfStuff is a [MyStuffClass]
    for thing in myVariadicListOfStuff {
        // this is a MyStuffClass
    }
}

      

+2


source







All Articles