4

I have function like:

void funcName(arg1, arg2, arg3[ = someDefault], ... , argN)

And I have a struct like

struct Args
{
    arg1;
    ...
    argN;
}

Is there any DRY and pretty solution to init structure from function args and to send structure into function if I can`t change function signature?

pvl
  • 958
  • 1
  • 6
  • 12
  • 1
    See the second answer in [this question](http://stackoverflow.com/questions/4203010/how-to-initialize-member-struct-in-initializer-list-of-c-class), it might help you do what you want. – Ryan J May 06 '15 at 19:38
  • C or C++? And then, are you using va_args or how exactly do you pass the variables? Do you know how many you have? Or is it totally variable? I'm guessing it is a fixed amount but could be wrong. – Khaldor May 06 '15 at 19:43
  • @Khaldor, yes, it`s fixed amount. But it`s can be changed some time! And I want to achive two goals: I want to operate with object, where I can(it`s much more comfortable) and I want to get compilation error, when something goes wrong(for example additional filed in object structure without function interface changing). Qusteion about C++, but I think that if there any solution for plain C it will works for C++ as well. – pvl May 06 '15 at 19:55

2 Answers2

3

Sure, but that's C++11.

struct xy {
    int x, y;
};

template <class... T>
xy f(T... args) {
    return xy{args...};
}

int main() {
    xy a = f(1, 2);
    cout << a.y << endl;
}

Live example.

By "sending structure into function" it seems you meant you'd like to get each field from a structure in the order they've been declared and call a function with them as arguments. Sorry, but there's no pretty way to do that, because that requires compile-time reflection, which is a subject to addition in further C++ versions, but the syntax is not even clear yet.

If you can use tuples instead of structures, it's easy though.

There's a not very much pretty way to do this if you absolutely need to. There's a Boost Fusion library. It allows adding reflection to structures via macros, so that it's possible to convert them to tuples.

polkovnikov.ph
  • 6,256
  • 6
  • 44
  • 79
  • I think he is looking for the inverse. Given a `struct`, call a function using the members of the `struct`. – R Sahu May 06 '15 at 19:38
  • @RSahu I think the OP wants to create the struct from the function `solution to init structure from function args` – NathanOliver May 06 '15 at 19:41
  • @pvl I've updated the post. Do you need an example of Boost Fusion usage? – polkovnikov.ph May 06 '15 at 19:44
  • @pvl so you also want to take all of the members of a struct and pass them as individual parameters to a function as well? – NathanOliver May 06 '15 at 19:45
  • Haha, BOOST_FUSION_ADAPT_STRUCT is basically a (slightly) prettier version of my solution :) – nneonneo May 06 '15 at 19:48
  • @NathanOliver, yes, you are right. @polkovnikov.ph Thx. About 'further C++ versions' - it`s just your guess or it`s officially already discussed somewhere? – pvl May 06 '15 at 19:48
  • @nneonneo That's exactly the reason why I've upvoted your answer :) – polkovnikov.ph May 06 '15 at 19:50
  • 1
    @pvl Yes, there's a mailing lists on several language proposals, and if I remember it right, it's called `SG7`. (Edit: https://groups.google.com/a/isocpp.org/forum/?fromgroups#!forum/reflection). – polkovnikov.ph May 06 '15 at 19:52
3

You can do it with macros. It's definitely not pretty, but it is highly compatible (works in C, C++03, etc.):

In header file args.h:

#define ARGS_STRUCT ARG(int, arg1) SEP ARG(char *, arg2) SEP ARG(void *, arg3)
#undef ARG
#undef SEP

You can declare the struct as

struct Args {
    #define ARG(type, name) type name
    #define SEP ;
    #include "args.h"
};

and the function as

int func(
    #define ARG(type, name) type name
    #define SEP ,
    #include "args.h"
);

initialize the struct with

struct Args args = {
    #define ARG(type, name) name
    #define SEP ,
    #include "args.h"
};

pass in args with

struct Args args;
func(
    #define ARG(type, name) args.name
    #define SEP ,
    #include "args.h"
);

Tested, no problems with Clang and Clang++ (both 6.1).

nneonneo
  • 171,345
  • 36
  • 312
  • 383
  • OMG. Sorry, but that it isn`t pretty – pvl May 06 '15 at 19:40
  • 1
    Hey, I told you it wasn't pretty. But C++ doesn't have very strong introspection skills - I'm pretty sure you cannot explode a struct into individual function arguments with the template system alone. – nneonneo May 06 '15 at 19:42
  • ...but, it does work, and you can probably define yourself some more macros to make it prettier :P – nneonneo May 06 '15 at 19:44
  • Actually this IS a a prettiest solution to the problem (modulo the existence of some libraries that will help you avoid some boilerplate). – polkovnikov.ph May 06 '15 at 19:49