In Rust, there is this crate which utilize Rust procedural macro to automatically implement builder pattern for any arbitrary struct defined. As there is no flexible way to instantiate Rust struct with some default and some provided values, this helps a lot in reducing boilerplate.
Is there any similar thing to generate builders automatically in C++, as instantiating objects in C++ also requires a lot of boilerplate (a lot of overloaded constructors to cover all posible combinations of fields or multiple steps initialization), possibly using C/C++ macros?
As the comments suggested, I added an example to clarify my idea. I want to instantiate class A below by just provide some field I want and leave others as default. If so, I either have to implement a lot of constructors or do multiple steps, instantiate and then override fields I want:
Multiple constructors
#include <string>
#include <iostream>
class A
{
public:
int a = 2;
std::string b = "b";
int c = 5;
std::string d = "d";
A() {}
A(int a) { this->a = a; }
A(std::string b) { this->b = b; }
A(int a, std::string b)
{
this->a = a;
this->b = b;
}
// ... more constructors to cover all combinations
// this might not even work as some combinations might
// have similar types, which prevent overloading them
};
Multiple steps
A a;
a.b = "hello";
a.c = 10;
Multiple steps instantiation is actually nice. However, it does not work if I want to have customized instantiation in 1 expression.
With builder pattern, I do that in 1 expression by chaining methods like this:
BuilderOfA()
.a(7)
.c(8)
.build();
Can the definition of this builder be automatically generated at compile time in C++? If not, is there anyway I can instantiate an object in a customizable way (by just provide some field I want and leave others as default) without using multiple expressions?
In c++ 20 you can do this:
struct S {
std::string str = "Hello";
float y = 1.0f;
int x = 10;
};
auto a = S{ .str = "Hi", .x = 8 };
Related
I have a class called system. A system takes some object managers and changes all objects in them in some way.
For example there might be a system that draws all images in a imageManager.
Every derived class works somewhat like this (pseudo code):
class someChildClass : public System{
private:
someObjectManager &mang1; //these are used by the update method.
someOtherObjectManager &mang2;//the update method changes these somehow
public:
someChildClass(someObjectManager &mang1, someObjectManager &mang2)
:mang1(mang1),mang2(mang2){
}
virtual void update(){
//this is pure virtual in the System base class.
//Do something with the managers here
}
}
I feel like writing everything but the update method is a waste of time and a source of errors. I wanted to write a macro that basically makes a class like this like so:
QUICKSYSTEM(thisIsTheSystemName, someObjectManager, mang1, someOtherObjectManager, mang2, ... (infinite possible Managers. So a variadic macro?)){
//this is the update function
}
}//this is the end braked for the class declaration. Its ugly but I dont know how I could do the function differently?
well I am having some problems making the macro. Everything works fine until I need to split the variadic arguments into the names and the types. I dont know if this is even possible now, since I cant go back and forth in the arguments easily or apply a easy step to them to make sure that every 2nd is the name of the variable. I would be ok with omitting the possibility for names and just had the types with some sort of automatic naming (manager1,manager2,manager3 or something like that).
If this isnt possible using a macro, what would be a better way to avoid mistakes and cut some time in the constructor and class declaration part?
Yeah, macros are really, really not the way to do this. C++ has templates, which follow C++ syntax and support C++ expressions. Macros instead use their own preprocessor language, which is almost entirely unaware of C++.
You'll want to read up a bit on std::tuple as well. It's going to be rather tricky to handle all those managers with those names. Tuples are the Standard solution for that. managers.get<0> and managers.get<someObjectManager> both work.
Variadic templates are the tool you need here:
#include <iostream>
#include <tuple>
#include <functional>
struct System { void virtual update() = 0; };
template<class... Managers>
struct ManagedSystem : System
{
std::function<void(Managers&...)> _update;
std::tuple<Managers&...> _managers;
template<class F>
ManagedSystem(F update, Managers&... managers) : _update(update), _managers(managers...) {}
void update() override { _update(std::get<Managers&>(_managers)...); }
};
int main()
{
int n = 0;
double d = 3.14;
auto reset = [](int& a, double& d) { a = 0; d = 0.0; };
ManagedSystem<int, double> ms{reset, n, d};
ms.update();
std::cout << "n = " << n << ", d = " << d << "\n";
// n = 0, d = 0
}
The idea is to define a templated-class (ManagedSystem) taking as template-parameters multiple manager types. This class inherits from Systemand provides a constructor taking:
an update functor,
and references to manager whose type is defined by the template parameters of the class.
The said managers are registered internally in an std::tuple and (with a bit of parameter pack magic fed to the update functor.
From there, you can define an inherited class from System by providing an update function and a type list. This avoids the use of ugly and type-unsafe macros in favor of the not-less ugly but type-string templates ;)
Disregarding whether the following can be achieved through other, more safe constructs - I'm simply interested in whether or not the following results in a well-defined output.
Assume you have a struct A:
struct A {
Foo* foo;
}
And a struct B inheriting from it:
struct B : A {
B() {
foo->some_function(); // UB
}
}
Sure enough if you were creating a B instance the normal way you'd trip UB, however...
template<typename R>
R make_A() { // This acts like a constructor for As
static_assert(std::is_base_of<A, R>::value, "R must derive from A");
char r[sizeof(R)];
((R*)r)->foo = returns_some_valid_foo();
new (r) R;
return *((R*)r);
}
B b1; // Blows up (Could you somehow prevent this from compiling without changing B?)
B b2 = make_A<B>(); // Works fine?
Sheepishly assuming that C++ works like C somewhere under the hood, I'm guessing that this would be similar to having a struct instance in C, initializing it by hand, and then calling some method (in this case B's constructor) on the finished product.
Again, I'm not interested in whether you should do this or not, it's just a technical question.
EDIT:
If you wonder what this could be useful for, I could use it to pull out values into a plain struct from, say, a configuration file in a really terse manner. Yes it does use macros but call it a stub until C++ gets compile time reflection:
#define config_key($x, $def) $x = foo->get<decltype($x)>(#$x, ($def))
struct Record : A {
int config_key(a, 3); // Second parameter is default value
string config_key(b, "something");
}
auto record = make_A<Record>();
(Using A and foo here to stay consistent with what I wrote above, make_A is actually part of a class that does config)
This:
((R*)r)->foo = returns_some_valid_foo();
is undefined behavior. There is no object of type R at r. Full stop. If you flip the two lines so that you create the R first, then you're fine (modulo r being insufficiently aligned).
Or really, just:
R r;
r.foo = returns_some_valid_foo();
return r;
I have a situation where I need to create instances of a class with many object pointer parameters. But, I'm looking for a simpler way. In this code sample, I demonstrate very generically what I'm trying to do.
#include <vector>
#include <string>
class A
{
public:
A(std::string param);
};
class B
{
public:
B(std::vector<A*> params);
};
int main(int argc, char* argv[])
{
std::vector<A*> my_arguments;
my_arguments.push_back(new A("A1"));
my_arguments.push_back(new A("A2"));
my_arguments.push_back(new A("A3"));
my_arguments.push_back(new A("A4"));
B my_b = new B(my_arguments);
}
I don't like having to use an additional 5 lines to create the parameters for this call. Is there an alternate way to do this that requires less code. I tried using an array like so, but it doesn't seem to be working:
B my_b = new B([new A("A1"), new A("A2"), new A("A3"), new A("A4")]);
How could I achieve a similar result? I thought about using va_list, but that would require another parameter marking the end, or a count of the number of variables. It might be what I end up doing, but, are there any other strategies out there?
You were nearly there...
B my_b{{new A("A1"), new A("A2"), new A("A3"), new A("A4")}};
Note: your code was trying to create B my_b which is not a pointer, so you don't need to use new. The outer { } pair surround the argument to the constructor, the inner { } pair create a std::initializer_list for the std::vector constructor, so the values therein are used to construct the std::vector argument.
Note that this syntax has been supported since C++11 - some compilers needs command line arguments to enable support for the C++11 Standard, e.g. gcc -std=c++11 ....
I can compose an AB struct that has all the members of structs A and B:
template AFields() {int a;}
struct A { mixin AFields; }
template BFields() {int b;}
struct B { mixin BFields; }
struct AB { mixin AFields; mixin BFields; }
A a; a.a = 1;
B b; b.b = 2;
AB ab; ab.a = 3; ab.b = 4;
But how can I construct AB, if I don't have control over A and B and I don't have AFields and BFields? I.e. how to write the CatStruct template so the code below compiles?
struct A { int a; }
struct B { int b; }
mixin CatStruct!("AB", A, B);
AB ab;
ab.a = 1; ab.b = 2;
The standard library has a few hidden jewels that I didn't actually even know about myself until I peeked at the source to answer this question:
http://dlang.org/phobos/std_traits.html#Fields
and the ones right under it too. With these, we can make your CatStruct fairly succinctly. Behold:
mixin template CatStruct(string name, T...) {
static import std.traits, std.conv;
private string _code_generator() {
string code = "struct " ~ name ~ " {";
foreach(oidx, t; T) {
foreach(idx, field; std.traits.FieldTypeTuple!t)
// this line is a monster, see the end of this answer
code ~= "std.traits.FieldTypeTuple!(T["~std.conv.to!string(oidx)~"])["~std.conv.to!string(idx)~"] "~ std.traits.FieldNameTuple!t[idx] ~ ";";
}
code ~= "}";
return code;
}
mixin(_code_generator());
}
This uses a string mixin though... and while string mixins can do basically anything, they also basically suck. This is liable to be brittle but I think it will basically work while basically sucking.
It also won't do struct methods, but I think that's too hard to realistically do with any of these magical things, except perhaps opDispatch, as seen in the other answer (which is pretty nice btw, don't take my answer as a repudiation of that one, just another idea).
If there's clashing names between the two structs too, they will break this, and you will get a hideously ugly error message out of the compiler. With a real template mixin, there's an easy fix for that - a named template mixin, which allows you to disambiguate. But no such thing here. I guess you could hack one in if you needed it.
But anyway, there might be a way to use those FieldTypeTuple and FieldNameTuple from the stdlib to do this even nicer, but I think it is more-or-less what you're asking for now.
BTW, I'd say just do ordinary composition if you at all can, it is going to work the best in general. (Don't forget about alias this too which can do automatic forwarding to member variables.)
If you haven't done a lot of mixins, you probably want to ask my why I used that crazy string in the code ~= part instead of the more straightforward. code ~= field.stringof ~ " "~ FieldNameTuple!t[idx] ~ ";";
tl;dr: just trust me, ALWAYS use local names available to the scope where you run the mixin() itself in the code you generate. Long explanation follows/
It has to do with name clashes and symbol lookups. I used static imports and fully qualified names in the mixed in code - including using the local symbol for the FieldTypeTuple rather than field.stringof - to keep this as namespace-tidy as possible.
Consider the case where struct A imports some other module internally and defines a field with it.
// using my color.d just cuz I have it easily available
// but it could be anything, so don't worry about downloading it
struct A { import arsd.color; Color a; }
AB ab;
import arsd.color;
ab.a = Color.white; ab.b = 2; // we expect this work, should be the same type
Since that's a local import inside struct A, the name is meaningless at the point of the mixin.
Go ahead and adjust the mixin so it compiles using the simple line
// comment fancy line
// code ~= "std.traits.FieldTypeTuple!(T["~std.conv.to!string(oidx)~"])["~std.conv.to!string(idx)~"] "~ std.traits.FieldNameTuple!t[idx] ~ ";";
// paste in simple line
code ~= field.stringof ~ " "~ std.traits.FieldNameTuple!t[idx] ~ ";";
And compile:
$ dmd f.d ~/arsd/color.d
f.d-mixin-31(31): Error: undefined identifier 'Color'
f.d(4): Error: mixin f.CatStruct!("AB", A, B) error instantiating
Zoinks! It had no idea what the string "Color" was supposed to refer to. If we imported some other kind of struct Color in the local module, it would compile.... but then it would refer to a different type:
struct A { import arsd.color; Color a; }
struct B { int b; }
struct Color { static Color white() { return Color.init; } }
mixin CatStruct!("AB", A, B);
AB ab;
import arsd.color;
ab.a = Color.white; ab.b = 2;
Compile it and see a silly sounding error:
$ dmd f.d ~/arsd/color.d
f.d(12): Error: cannot implicitly convert expression (white()) of type Color to Color
BTW: remember this if you ever see it in the wild - the compiler error message sounds absurd, "cannot implicitly convert Color to Color", but it actually does have a logical meaning: there's just two different types with the same name in different modules.
Anyway, it sounds silly, but makes sense because the two scopes imported different structs.
With the long-form FieldTypeTuple used with a local static import, it always refers to the actual type passed in. Indirectly, sure, but also unambiguously.
I apologize to those reading this who already know about the pitfalls of string mixins, but anyone finding this on a search might not know why I used that convoluted code. It is complex due to real world experience with actual problems, I swear! :) It is a lot easier to do it right the first time than try to debug the weird nonsense down the road it can bring doing it the other way.
There's a lot of ground to cover here (members, functions, templates, ect.).
However, here's an idea to get you started:
import std.typecons;
struct A { int a; }
struct B { int b; }
struct AB
{
mixin MultiProxy!(A, B);
}
mixin template MultiProxy(A, B) {
private A _a;
private B _b;
mixin Proxy!_a aProxy;
mixin Proxy!_b bProxy;
template opDispatch(string op) {
static if (is(typeof(aProxy.opDispatch!op))) {
alias opDispatch = aProxy.opDispatch!op;
}
else {
alias opDispatch = bProxy.opDispatch!op;
}
}
}
unittest
{
AB ab;
ab.a = 4;
ab.b = 5;
assert(ab.a == 4);
assert(ab.b == 5);
}
I haven't had time to thoroughly test this, so I wouldn't be suprised if there are a number of areas where it falls over (just look at the implementation of Proxy to see all the things it has to take into account).
However, the general idea is to create two proxies, each explicitly named (aProxy,bProxy) so we can explicitly call the opDispatch of either one depending on which will compile.
In the interest of completeness, here's a solution that uses named tuples:
import std.meta, std.traits, std.typecons;
// helper template to interleave 2 alias lists
template Interleave(A...)
{
static if(A.length == 0)
alias A Interleave;
else
alias AliasSeq!(A[0], A[A.length/2],
Interleave!(A[1..A.length/2], A[A.length/2+1..$])) Interleave;
}
// helper template to produce tuple template parameters
template FieldTypeNameTuple(A)
{
alias Interleave!(Fields!A, FieldNameTuple!A) FieldTypeNameTuple;
}
template CatStruct(A...)
{
alias Tuple!(staticMap!(FieldTypeNameTuple, A)) CatStruct;
}
// usage
struct A { int a; }
struct B { int b; }
struct C { int c; }
alias CatStruct!(A, B, C) ABC;
I am trying to make it possible for a programmer (who uses my library) to create nameable instances of type X that are stored inside an instance of class C (or at least are exclusive to that instance).
These are the only two (ugly) solutions I have managed to come up with (needless to say, I am just picking up C++)
1)
class C
{
public:
class XofC
{
public:
XofC() = delete;
XofC(C& mom)
{
mom.Xlist.emplace_front();
ref = Xlist.front();
}
X& access()
{
return ref;
}
private:
X& ref;
};
//etc
private:
std::forward_list<X> Xlist;
friend class XofC;
//etc
}
Problem:
Having to pass everywhere XofC instances.
2)
class C
{
public:
void newX(std::string);
X& getX(std::string);
//etc.
private:
/*possible run-time mapping implementation
std::vector<X> Xvec;
std::unordered_map<std::string, decltype(Xvec.size())> NameMap;
*/
//etc
}
Problem:
This does the job, but since all names of X (std::string) are known at compilation, the overhead of using run-time std::unordered_map<std::string, decltype(Xvec.size())> kind-of bugs me for something this simple.
Possible(?) solution: compile-time replacing of std::string with automatic index (int). Then I could use:
class C
{
public:
void newX(int); //int: unique index calculated at compile time from std::string
X& getX(int); //int: unique index calculated at compile time from std::string
//etc.
private:
std::vector<X> Xvec;
}
Questions:
Is there a 3)?
Is a compile time solution possible for 2)?
This is the real-life situation: I was starting my first C++ "project" and I thought I could use the practice and utility from an awesome user-friendly, simple and fast argument management library. I plan to make an ArgMan class which can parse the argV based on some specified switches. Switches would be named by the programmer descriptively and the trigger strings be specified (e.g. a switch named recurse could have "-r" and "-recursive" as triggers). When necessary, you should be easily able to get the setting of the switch. Implementation detail: ArgMan would have a std::unordered_map<std::string/*a trigger*/, ??/*something linking to the switch to set on*/>. This ensures an almost linear parse of argV relative to argC. How should I approach this?
You could 'abuse' non-type template arguments to get compiletime named instances:
Live on Coliru
Assume we have a data class X:
#include <string>
struct X
{
int has_some_properties;
std::string data;
};
Now, for our named instances, we define some name constants. The trick is, to give them external linkage, so we can use the address as a non-type template argument.
// define some character arrays **with external linkage**
namespace Names
{
extern const char Vanilla[] = "Vanilla";
extern const char Banana [] = "Banana";
extern const char Coconut[] = "Coconut";
extern const char Shoarma[] = "Shoarma";
}
Now, we make a NamedX wrapper that takes a const char* non-type template argument. The wrapper holds a static instance of X (the value).
// now we can "adorn" a `namedX` with the name constants (above)
template <const char* Name>
struct NamedX
{
static X value;
};
template <const char* Name> X NamedX<Name>::value;
Now you can use it like this:
int main()
{
X& vanilla = NamedX<Names::Vanilla>::value;
vanilla = { 42, "Woot!" };
return vanilla.has_some_properties;
}
Note that due to the fact that the template arguments are addresses, no actual string comparison is done. You cannot, e.g. use
X& vanilla = NamedX<"Vanilla">::value;
becuase "Vanilla" is a prvalue without external linkage. So, in fact you could do without some of the complexity and use tag structs instead: Live on Coliru
While Neil's solution did what I asked for, it was too gimmicky to use in my library. Also, sehe's trick is surely useful, but, if I understood correctly, but doesn't seem related to my question. I have decided to emulate the desired behavior using method 1), here is a less broken attempt at it:
class C
{
private:
class X
{
//std::string member;
//etc
};
public:
class XofC
{
public:
XofC(C & _mom) : mom(_mom)
{
mom.Xlist.emplace_front();
tehX = &(Xlist.front());
}
X & get(maybe)
{
if (&maybe != &mom) throw std::/*etc*/;
return &tehX;
}
private:
X * tehX;
C & mom;
};
private:
//etc
std::forward_list<X> Xlist;
friend class XofC;
//etc
};
Usage:
C foo;
bar = C::XofC(foo); //acts like an instance of X, but stored in C, but you have to use:
bar.get(foo)/*reference to the actual X*/.member = "_1_";
Of course, the downside is you have to make sure you pass bar everywhere you need it, but works decently.
This is how it looks like in my tiny argument manager library:
https://raw.github.com/vuplea/arg_manager.h/master/arg_manager.h