Statically initialize nested C++ structures with named labels using g++ - c++

I am importing/porting existing C code to C++. I am hoping to make as few changes to the existing body of code as possible to minimize preterbing the existing code.
This code makes use of static named initialization of nested structures. For quick made up example:
Car car =
{
.color = RED,
.tire.tread = OLD,
.tire.diameter = 27.106,
.tire.material.type = RUBBER,
.tire.material.density = 700,
};
I figured out that these are called designated initializers.
I learned about GNU initializers but I haven't figured out how to implement hierarchy with it.
I read that designated initializers are supported in g++ with c++11 enabled, but that didn't seem to work for me.
The code I am porting has pages of initialization with at least four layers deep of hierarchy. So I am trying to look for a straightforward transformation which doesn't get too involved.
I am looking for one of these possible solutions:
How to enable C99 designated initializers
How to formulate hierarchical GNU style initialization
What is a C++ equivalent way to do this which wouldn't be error prone transcribing war and peace.
An obvious solution I haven't thought of
I am using g++ version
g++.exe (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 8.1.0

The use of such nested designated initializers seems to be something of an edge case. The following works in both clang-cl (in Visual Studio 2019) and the native MSVC compiler (but the latter only with the /std:c++latest option, which uses the draft C++20 standard):
struct inner {
int x, y;
double z;
};
struct outer {
char a;
double b;
inner c;
};
outer my_outer = { .a = 'a', .b = 1.2, .c = { .x = 3, .y = 4, .z = 5.6 } };
With clang-cl, the initializer can be abbreviated to the following form:
outer my_outer = { .a = 'a', .b = 1.2, .c.x = 3, .c.y = 4, .c.z = 5.6 };
but MSVC complains in this case, with:
error C7558: nested member access is not allowed in standard C++
designated initializers; use a nested initializer list
So, for your example, you could try this:
Car car =
{
.color = RED,
.tire = {
.tread = OLD,
.diameter = 27.106,
.material.type = RUBBER,
.material.density = 700,
}
};
There's a helpful 'discussion' of the topic on cppreference, with this part being notable:
...each designator must name a direct non-static data member of T, and
all designators used in the expression must appear in the same order
as the data members of T.

Related

Initialising variables in C++ with {}

I am using C++ in Visual Studio Code. When I want to initialise a variable I cannot initialise it with {} (e.g., int x {0};). Instead, I have to use () (e.g., int x (0);).
The error I get when using {} is "error: expected ';' at end of declaration" Although I have put ; at the end of declaration.
I'm using clang 11.0.0 as the compiler. Is it related to the compiler?
The code runs through the terminal by ./filename command. However, it gives errors when running by coderunner extension in VSCode.
In order to initialize a variable with {} you must say it is = {}.
Like this:
int x = {3}; //you wouldn't really do this for simple variable though I don't think since you can just say int x = 3;
//or if you are making a custom object you might say:
MyObject object = {"apples", 3, "red"};
// to set the variables inside the object. in the order they are declared.
I hope this answers your question!

Porting structs to MSVC 2017

how can I port the following Linux declaration to MSVC? "Expected identifier" is what I get as an error.
static const struct tap_align_size align_size_000000_00[] = {
[0] = {.align = 1,.size = 4, },
[52] = {.align = 1,.size = 4, },
};
where
struct tap_align_size {
uint8_t align:4, size:4;
};
You would have to make a struct with a constructor (with an array within) or laboriously type {} 51 times. The latter possibility is more risky because you do not know the order of fields in the struct, and even if you knew, a newer version could shuffle them, with the compiler unable to detect the change.

C++ enum definitions not being accepted

I would like to use some nss3.dll code in my program. To do this I decided to declare all of the compound datatypes that it needs and call the functions inside the dll file with them.
I am using a file in the firefox source code to see how to properly use the functions I need. In one of the functions it declares one of these compound datatypes (secuPWData) and passes it variables. Here is the definition I pasted into my code without any errors:
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
char *data;
} secuPWData;
The declaration of this struct looks like this in the code I'm looking at: secuPWData pwdata = { PW_NONE, NULL };
When I try to use a similar (or even the same) declaration, it complains about the PW_NONE attribute, claiming it is undefined. When I tried to pass in the 0 value in its place, it told me that 'a value of type "int" cannot be used to initialize an entity of type "enum secuPWData::"'. To try to debug the issue, I tried pasting the definition right on top of the declaration, without any change.
What is causing this problem to occur?
Thanks for any help.
just as #n.m. mentioned try using secuPWData::PW_NONE
#include <iostream>
using namespace std;
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
char *data;
} secuPWData;
int main() {
secuPWData pwdata = { secuPWData::PW_NONE, NULL };
return 0;
}
worked for me .. ideone - link

intermittent error returning an internal reference with boost.python

I have the following class:
#include <array>
template<unsigned short D>
class Point {
private:
std::array<float, D> coordinates;
public:
Point() { for(int i=D-1; i>=0; --i) coordinates[i] = 0.0; }
Point(const Point& rhs) = default;
Point& operator=(const Point& rhs) = default;
~Point() = default;
float& get_ref(const unsigned short dimension)
{ return coordinates[dimension-1]; }
};
I'm trying to wrap it with:
#include <boost/python.hpp>
BOOST_PYTHON_MODULE(fernpy) {
using namespace boost::python;
class_< Point<2> >("point")
.def("__call__", &Point<2>::get_ref, return_internal_reference<>());
}
I'm using gcc-4.7 to compile for boost 1.48, python-2.7 on Fedora 17. All the code is a file called testpy.cpp. I'm using these commands to compile:
g++ -std=c++11 -g -fPIC -I/usr/include/python2.7 -c testpy.cpp
g++ -shared -g -lpython2.7 -lboost_python -o libfern.so testpy.o
The compiler returns a bunch of boost internal errors, too many to post here. This excerpt seems to be the core of it. There are a bunch of "required from"s before it and "note"s after.
/usr/include/boost/python/object/make_instance.hpp:27:9: error: no matching function for call to ‘assertion_failed(mpl_::failed************ boost::mpl::or_<boost::is_class<float>, boost::is_union<float>, mpl_::bool_<false>, mpl_::bool_<false>, mpl_::bool_<false> >::************)’
It works just fine if I return a plain float from get_ref and remove the return_internal_reference<>() argument from the .def line of the wrapper. It's weird because I'm doing the same thing with another, more complicated class template and it works just fine there too. I've been Googling and banging my head against this for almost a full day now. Anybody have any idea what the heck is going on?
UPDATE:
I ended up using the "getitem" and "setitem" special methods from python, a la this link. The link shows how to define a nifty struct template with static wrappers for access functions, so you don't have to mess with the interface to your original C++ class.
From a python point-of-view, floats are an immutable-type. As such, python does not allow changing the value.
For example, the following occurs in python:
coordinates = [ 5, 10, 15 ]
x = cooardinates[ 2 ] # Bind x to refer to the int(15) object.
x = 5 # Rebind x to refer to the int(5) object.
# Does not modify coordinates.
Now, consider the following:
from fernpy import point
p = point()
x = p(2) # Bind x to refer to the float(p(2)) object.
x = 5 # Rebind x to refer to the int(5) object.
# Does not set p.coordinates[2] to 5.
Thus, boost::python prevents returning reference to types that will be immutable in python because Python does not support it. x does not store the value 5; instead, it contains a reference to the 5 object. If assigning to x did not rebind x, then nonsensical statements, such as 6 = 5 would be possible.
The compile error is a static check that limits return_internal_reference to only work with classes or unions, as those will be mutable types within Python. I imagine that the 'more complicated class template' that works is returning a reference to a user-type.
The short answer is probably that you don't want to return an internal reference to a float. In Python, numbers are immutable, so just returning a copy is safer, and sacrifices no features or speed.
If you want to return something more complicated (such as a list or reference to another wrapped class), you can, but it's still almost always not what you want; the dependency of one object on the other introduces fragility. If you want to be able to modify the internal state of an object, you're probably better off using getters and setters, and copying the data in and out.

Union initialisation in a struct

I've been browsing stackoverflow concerning the problem of initialising a union in a struct but I didn't manage to get it right.
Here is my struct
typedef struct dc_netif_filter {
unsigned char filter_type;
union {
uint32_t itf_nb;
char * buf;
} value;
} dc_netif_filter_t;
In my code, i have tried to use :
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,{{0, "tun"}}};
which gives error: braces around scalar initializer for type ‘uint32_t’
and
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,{0, "tun"}};
which gives error: too many initializers for ‘dc_netif_filter::< anonymous union>’
How do i declare such a dc_netif_filter_t ?
I'm using g++ on ubuntu. Note that the dc_netif_filter_t isn't a struct that I can modify as it comes from a third party project.
**EDIT : as I've been explained, i can only initialise one field. The problem is that with
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,"tun0"};
I get a conversion error : invalid conversion from ‘const char*’ to ‘uint32_t
Thanks
As the compiler says, too many initializers for ‘dc_netif_filter::< anonymous union>’.
Initialize only one field, not both.
Use the name of the field to initialize it properly:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, { buf: "tun0" }};
It looks like you are trying to initialize your structure to indicate that the buf member is to be used, and that the value of that buf should be "tun". Since C++ before C++11 lacks designated initializers, you cannot do it with an initializer: only the first field of the union can be initialized, so you need to do your assignment in code:
static get_dc_netif_filter_t() {
static c_netif_filter_t netif = {DC_NETIF_SELECT_NAME, {0}};
if (netif.value.itf_nb == 0) {
netif.value.buf = "tun";
}
return netif;
}
C++11 lets you do it like this:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, { .buf = "tun"}};
This works under g++ 4.7.0:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, {.buf="tun"}};
Although designated initializers are supposed to be C only, not C++! Maybe it's a GNU extension?
I guess the best (most compatible) way is to assign the members after initialization:
dc_netif_filter_t netif;
netif.itf_nb = DC_NETIF_SELECT_NAME;
netif.value.buf = "TUN";