C++ anonymous struct as std::map value - c++

I am using Visual Studio 2019 std:c++ 17 which supports anonymous struct, f.e.
struct S
{
struct { int i; };
};
However, the following code has compile errors.
map<int, struct { int i; }> m;
Can I use anonymous struct as value type of std::map?

You can't do it directly, but indirectly, either
struct { int i; } s;
std::map<int, decltype(s)> a;
or
using MyType = struct { int i; };
std::map<int, MyType> b;
but note that a and b will be of different type. decltype(s) is not the same type as MyType.

Anonymous structure is a structure that is defined within another class (structure). So you can not use such a structure inside a container because in this case it will not be an anonymous structure but will be just an unnamed structure.
In this record (that is incorrect)
map<int, struct { int i; }> m;
there is no anonymous structure. There is an attempt to use an unnamed structure.
You could write for example
#include <iostream>
#include <map>
int main()
{
using S = struct { int i; };
std::map<int, S> m;
}
But as I said there is no anonymous structure.
Here is the definition of the notion anonymous structure (the C Standard, 6.7.2.1 Structure and union specifiers)
13 An unnamed member of structure type with no tag is called an
anonymous structure;

Related

Redeclare variable inside enum

In C, If we re-declare variable inside enum, then compiler gives an error that "'i' redeclared as different kind of symbol".It Ok.
#include <stdio.h>
int i = 10;
struct S
{
enum
{
i = 20
}e;
};
int main()
{
printf("%d\n", i);
}
But, In C++, If we redeclare variable inside enum, then it's working fine.
#include <iostream>
using namespace std;
int i = 10;
struct S
{
enum
{
i = 20
}e;
};
int main()
{
cout<<i<<endl;
}
I don't understand, Why doesn't C++ compiler gives an error for redeclaration variable?
It doesn't give a re-declaration error because the enumerator is introduced into class scope. Recall that a struct and class are mostly interchangeable in C++. The scope of S contains the enumerator i.
In C however, struct S doesn't define a scope. There are only 4 types of scope in C: function, file, block, and function prototype. As such, i is introduced into file scope where the variable i is already defined.

Is there another reason for using tags in typedef except for self referencing?

If I want to create a new struct type that contains a pointer the type itself I wouldn't be able to do
typedef struct {
my_type* p;
} my_type;
and I will need to use a tag
typedef struct my_tag {
struct my_tag* p;
} my_type;
Is there another use for the tag mechanism? because I've seen it several times and I don't understand why someone would add this to a typedef
Also, since C and C++ are a bit different with their struct keyword, would that change anything if I typedef such a struct in C or in C++?
Another use is "opaque type", which is usually forward- declared as
typedef struct my_type my_type;
where you want to define a type at the same time as you do a forward declaration. typedef struct my_type; would have been nonsense. In general, you can't forward-declare without a struct tag.
I looked over the comments and answer, but never saw this. It seems too obvious for someone to not have already brought it up, so I apologize if this duplicates a response.
In C++, you don't use typedef struct. Instead, add a forward declaration of the incomplete type to the member's declaration:
#include <iostream>
struct my_type {
int i;
struct my_type* p;
};
int main() {
my_type my_obj;
my_obj.i = 100;
my_obj.p = &my_obj;
std::cout << my_obj.p->i << '\n';
}

Filling a List with struct

I'm new to C++/CLI and are having a hard time with Lists.
I have a structure
#using namespace System::Collections::Generic
struct myStruct {
unsigned int A ;
int B; };
and i want to create a list with mystructs
List<myStruct> myList;
But that seems not to work, Visual Studio says
"myStruct is not a valid generic Argument", but why is that so?
And how can i make this structure a "valid generic argument"?
#include <List>
struct myStruct {
unsigned int A ;
int B;
};
std::list<myStruct> myList;
int main(void) {
return 0;
}

`std::pair` `second` has incomplete type with `unordered_map` tree

I was reviewing some older code of mine and I saw the code using pointers to implement a tree of Variant objects. It is a tree because each Variant can contain an unordered_map of Variant*.
I looked at the code and wondered why isn't it just using values, a std::vector<Variant>, and std::unordered_map<std::string, Variant>, instead of Variant*.
So I went ahead and changed it. It seemed okay except one thing, I got errors:
/usr/local/include/c++/6.1.0/bits/stl_pair.h:153:11: error: 'std::pair<_T1, _T2>::second' has incomplete type
_T2 second; /// #c second is a copy of the second object
^~~~~~ main.cpp:11:8: note: forward declaration of 'struct Variant'
struct Variant
^~~~~~~
So I figured I could trick the compiler into delaying the need to know that type, which didn't work either.
Working Not Working! (MCVE)
I thought this worked earlier but it actually doesn't, I forgot ::type on the using HideMap...
#include <vector>
#include <unordered_map>
#include <iostream>
template<typename K, typename V>
struct HideMap
{
using type = std::unordered_map<K, V>;
};
struct Variant
{
using array_container = std::vector<Variant>;
// Does not work either
using object_container = typename HideMap<std::string, Variant>::type;
// Fails
//using object_container = std::unordered_map<std::string, Variant>;
private:
union Union
{
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
Union data;
bool weak;
};
int main()
{
Variant v;
std::cout << "Works" << std::endl;
}
So, my question is, why does it work okay for vector and not unordered_map?
If the problem is the inability to use incomplete types, is there a way to delay the instantiation of the unordered_map? I really don't want every object property to be a separate new allocation.
This uses placement new to defer the initialization of the Union to the constructor where Variant is a complete type. You need to reinterpret_cast everywhere you need to use the Union. I made an effort to not have any strict-alignment violations.
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
struct Variant {
Variant();
~Variant();
private:
std::aligned_union<0, std::vector<Variant>,
std::unordered_map<std::string, void *>,
std::int64_t>::type data;
};
namespace Variant_detail {
using array_container = std::vector<Variant>;
using object_container = std::unordered_map<std::string, Variant>;
union Union {
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
}
Variant::Variant() {
//make sure that std::unordered_map<std::string, Variant> is not too large
static_assert(sizeof(std::unordered_map<std::string, Variant>) <=
sizeof data, "Variant map too big");
static_assert(alignof(std::unordered_map<std::string, Variant>) <=
alignof(decltype(data)), "Variant map has too high alignment");
auto &my_union = *new (&data) Variant_detail::Union;
my_union.vint = 42;
}
Variant::~Variant() {
reinterpret_cast<Variant_detail::Union &>(data).~Union();
}
int main() {
Variant v;
std::cout << "Works" << std::endl;
}

Struct with Vector of Structs

Sorry, the title sounds a little confusing, let me explain.
I have a struct, which has a vector of structs, like this:
struct foo {
int x;
vector < foo > bar;
};
But I get an error of "No Instance of Overloaded Method" when I try this syntax:
foo a;
foo b;
b.x = 3;
a.bar.push_back(b);
Basically, I am just trying to create a "relationship" between a and b, with bar being the relationship vector containing all related instances of foo.
Any suggestions?
Your code is, unfortunately, illegal according to the C++ Standard, because you are passing an incomplete type as a template parameter to the Standard Library, which is prohibited in general and std::vector doesn't have an exception to the general rule.
The Boost documentation has a great explanation.
You can either use a container which explicitly supports incomplete types, as the Boost ones do, or use std::vector<std::unique_ptr<foo>>, because the Standard says in 20.9.1p5:
The template parameter T of unique_ptr may be an incomplete type.
May be it's your compiler, Mine gives no error or warnings.
#include <iostream>
#include <vector>
using namespace std;
struct foo {
int x;
vector < foo > bar;
};
int main()
{
foo a;
foo b;
b.x = 3;
a.bar.push_back(b);
cout<<a.bar[0].x;
cout<<"\n";
return 0;
}