constructing a pair(string, *node) to insert into an unordered_map - c++

typedef unordered_map<string, relationNode*> relationMap;
using relation_entry = relationMap::value_type;
void insertNode(string category, relationNode* node) {
relation_entry insertPair =
make_pair<string, relationNode*>(category, node);
}
causes an error of "cannot convert 'category' (type 'std::string(aka std::basic_string(char))') to type 'std::basic_string(char)&&"
and an error of "cannot convert 'node' (type 'relationNode*') to type 'relationNode*&&".
I was planning to make the pair then insert it into a unordered_map.
I am using "g++ -g -O0 -Wall -Wextra -std=gnu++11" to compile the code. Any help will be greatly appreciated.

Just write:
relation_entry insertPair =
make_pair(category, node);
This will work and be more concise (in fact, that's the reason you use std::make_pair instead of calling the constructor directly in the first place).
You should know that this is a backward-compatibility issue with C++11. Consider this piece of C++98 code (I replaced unordered_map with map and using with typedef):
#include <map>
#include <string>
using namespace std; // just for testing
struct relationNode {};
typedef map<string, relationNode*> relationMap;
typedef relationMap::value_type relation_entry;
void insertNode(string category, relationNode* node) {
relation_entry insertPair =
make_pair<string, relationNode*>(category, node);
}
int main() {
}
Go to http://cpp.sh/ and try to compile it. You will see that it compiles fine in C++98 mode but not in C++11 and C++14 modes.
For a detailed explanation of the issue, see C++11 make_pair with specified template parameters doesn't compile
Bottom line: Don't specify redundant type arguments and you'll be fine.

Related

Compiler errors with incorrect use of nullptr

I am trying the solution provided in this SO Q/ACompiler error while using shared_ptr with a pointer to a pointer and I am not able to use the solution provided in a proper way. I still get compilation errors on Ubuntu 18.04 with g++ version 7.3
Here is my minimum complete verifiable example to reproduce the problem
test.h
# include <memory>
using std::shared_ptr;
using std::unique_ptr;
struct DataNode
{
shared_ptr<DataNode> next;
} ;
struct ProxyNode
{
shared_ptr<DataNode> pointers[5];
} ;
struct _test_
{
shared_ptr<shared_ptr<ProxyNode>> flane_pointers;
};
test.cpp
#include <stdint.h>
#include "test.h"
shared_ptr<DataNode> newNode(uint64_t key);
shared_ptr<ProxyNode> newProxyNode(shared_ptr<DataNode> node);
struct _test_ test1;
int main(void)
{
test1.flane_pointers(nullptr);
shared_ptr<DataNode> node = newNode(1000);
}
shared_ptr<ProxyNode> newProxyNode(shared_ptr<DataNode> node) {
shared_ptr<ProxyNode> proxy(new ProxyNode());
return proxy;
}
shared_ptr<DataNode> newNode(uint64_t key) {
shared_ptr<DataNode> node(new DataNode());
return node;
}
This is the error I get
test.cpp: In function ‘int main()’:
test.cpp:11:31: error: no match for call to ‘(std::shared_ptr<std::shared_ptr<ProxyNode> >) (std::nullptr_t)’
test1.flane_pointers(nullptr);
^
What else have you tried ?
I tried initializing the nullptr in the header file as well
struct _test_
{
shared_ptr<shared_ptr<ProxyNode>> flane_pointers(nullptr);
};
But that did not work either. Where am I going wrong ?
My Goal
All I am trying to do is the following - I am trying to initialize flane_pointers which is a vector of pointers to a nullptr. The declaration has been made in a header file as to what type it is and I am trying to initialize it in a .cpp file. While doing that I get the above compilation errors.
flane_pointers(nullptr)
UPDATE
Could any of the answers explain whether the initialization provided in this Compiler error while using shared_ptr with a pointer to a pointer correct or not ?
std::shared_ptr<std::shared_ptr<ProxyNode> > ptr2ptr2ProxyNode(nullptr);
To me (and I am a newbie to C++) that initialization looks like a function call as well. Is that incorrect ?
On this line:
test1.flane_pointers(nullptr);
You're trying to call flane_pointers as though it were a member function. shared_ptr can't be called like a function, so you get the compiler error.
If you want to initialize flane_pointers, you can just assign to it:
test1.flane_pointers = nullptr;
Or alternatively, you could do the assignment when you create test1:
// Initialize test1 with a nullptr
_test_ test1{nullptr};
If your intent is to initialize flane_pointers to nullptr, you should use initialization of the below form:
shared_ptr<shared_ptr<ProxyNode>> flane_pointers = nullptr;
in struct _test_
or
test1.flane_pointers = nullptr;
in main.
The other form of initialization you are trying to do is interpreted as a function call in main and as a function declaration in struct _test_.
In the linked post,
std::shared_ptr<std::shared_ptr<ProxyNode> > ptr2ptr2ProxyNode(nullptr);
is in main and can only be interpreted as a variable declaration and not a function call because it does not have a function call syntax as the variable is preceded by the type std::shared_ptr >.
To avoid confusion, it is better (from C++11 onwards) to declare and initialize variables with the brace-enclosed initializer {}.
The line
test1.flane_pointers(nullptr);
is treated a function call. That's the source of the error. Use assignment instead.
test1.flane_pointers = nullptr;
And
shared_ptr<shared_ptr<ProxyNode>> flane_pointers(nullptr);
is not a valid form of in-member initialization. You may use
shared_ptr<shared_ptr<ProxyNode>> flane_pointers{nullptr};
or
shared_ptr<shared_ptr<ProxyNode>> flane_pointers = nullptr;

Why can you assign nullptr to std::string?

So today I wrote a fairly hard to find bug where I initialized a std::string to nullptr (not a pointer to std::string, but the value itself). I've found apparently it's only possible to do in C++11 or later with clang.
#include <string>
#include <iostream>
using namespace std;
class Meh{
int x;
};
class Foo
{
private:
std::string x=nullptr;
Meh y=nullptr; //remove this line and it compiles
public:
std::string z=nullptr;
};
int main(void)
{
Foo f;
cout << f.z;
return 0;
}
As you can see, I tried assigning nullptr to just a random instance of a class and it didn't work. What magic is in string that allows this to work, and in what way is this even valid syntax? I assumed I would be met with a type casting error in this case.
For reference I compiled with this:
clang++ test.cpp -O3 -g -fno-inline -std=c++11 -Wall
It gave no form of warnings, though it would error out if not using C++11
That's simply because there are constructors (number (5) in the link) and assignment operators (number (3) in the link) for std::string that accept a const char*, and hence the nullptr matches.
Before C++11 (and therefore before nullptr), the same problem occurred when you tried to construct from 0 or NULL. All those cases were illegal and result in undefined behaviour, although at least one STL (RogueWave?) accepted it in the past and generated an empty string.

Intel C++ error: "pair" is not a nonstatic data member or base class of class "std::pair<const int, double>"

I'm using Intel C++ compiler together with qmake in QtCreator. In my project I use a std::map.
std::map<int,double> dataBase;
dataBase[2] = 2.445;
This code compiles and runs without any problems using g++. If I try to compile with ICC the following error occurs:
/usr/include/c++/4.8.0/tuple(1075): error: "pair" is not a nonstatic data member or base class of class "std::pair<const int, double>"
Full compiler error is much longer. I'm a little confused about the include path because for me it looks like a g++ library which is used. If I comment out this section program compiles and I can verify that the ICC was used.
Does anybody know why the Intel C++ compiler causes this error?
Edit:
I create a minimal example and found the compiler option causing this problem:
Folowing is content of the *.pro file
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += main.cpp
QMAKE_CXXFLAGS += -std=c++11
main.cpp
#include <iostream>
#include <map>
using namespace std;
int main(){
map<int,double> dataBase;
dataBase[2] = 2.445;
cout << dataBase[2] << endl;
return 0;
}
It works without the
-std=c++11
but causes compiler error with it.
I am having the same problem as you are describing..., really strange. Every other compiler (clang, gcc, msvc11) compiles it without any problem. I guess it's because of the 4.8.x headers. icpc -v says at least version 13.1.1 (gcc version **4.7.0** compatibility)...
Workaround:
template<class K, class V>
V &changemapvalue(std::map<K, V> &map, K &key, V &val)
{
#if defined(__GNUC__) && defined(__INTEL_COMPILER)
if (map.find(key) != map.end()) map.erase(key);
map.insert(std::pair<K, V>(key, val));
#else
map[key] = val;
#endif //__GNUC__ && __INTEL_COMPILER
return val;
}
But it's stupid.
If you consider a vector<char>, a single element is represented as simply a char.
A map however (and the other associative containers) are not represented this way. Rather, they are represented as a pair:
{C++03} 23.3.1/2
typedef pair<const Key, T> value_type;
I'm not familiar with the Intel C++ compiler, but judging from the error message I'd say that Intel implements pair in terms of a tuple class. A tuple class is an N-ary aggregate of things. A pair for example would be a tuple with two elements.
All of the above is simply elaboration, and doesn't really speak to why you're getting this error. /usr/include/c++/4.8.0 looks to me like the include directory for G++ 4.8.0 -- the latest version of G++. If the Intel compiler is looking here, I'd say your paths are messed up, either in your environment or in the paths sent to the Intel compiler.
Check your environment variables and your makefile.
When it comes to c++11 for some reasons icpc doesn't like the operator[] of std::map.
For inserting new values you need to use the method insert() while to access existing values you can use the c++11 method at().
This compiles correctely with icpc -std=c++11
#include <iostream>
#include <map>
using namespace std;
int main(){
map<int,double> dataBase;
dataBase.insert(pair<int,double>(2,2.445));
cout << dataBase.at(2) << endl;
return 0;
}

Incomplete types with Clang compiling c++11 code

As this website shows, following code will not be supported in Clang using C++11:
class Node {
vertex<Node> children;
};
An error will occur:
field has incomplete type 'Node'
But such code is supported in C++98 and other compilers such as gcc in C++11.
I know I can use
vertex<Node*>
instead, but at present I have some incompatibility issue with old code in C++98.
My question is, (1) can I compile such code using Clang in C++11? (2) I think a tree structure does inevitably need definition like above, without support of such feature, how can I realize such tree structure?
update:
Sorry for forgetting to give definition of vertex, What about the following code:
class Node {
vector<Node> children;
};
Just change vertex into a container vector. It is not valid in Clang with C++11, but ok with other compilers and with C++98.
update again:
It seems vector works OK..but list fails
class Node {
std::list<Node> children;
};
update again:
Following is my code:
#include <list>
using namespace std;
class Node {
list<Node> nodes;
};
int main(int argc, char const *argv[])
{
return 0;
}
or simpler:
#include <list>
class Node {
std::list<Node> nodes;
};
int main() {}
I'm using Clang 4.0 and using the following command to compile:
clang++ -std=c++11 -stdlib=libc++ test.cpp
The error is
/usr/bin/../lib/c++/v1/list:212:9: error: field has incomplete type 'Node'
If it does not compile, it means that vertex attempts to use Node in a way that requires it to be completely defined. Most of the time, this implies (for generic code) using the size of the T parameter:
either explicitly (sizeof(T))
or implicitly template <typename T> struct vertex { T data[3]; }; is using the size of T to compute the layout of the type
Another (possible) issue, is relying on methods of T for some template instantiation; however this is much rarer.
You can avoid this requirement by changing the definition of vertex. Not knowing what it is though, we won't be able to get much more specific...

C code does not work when coded like C++

Hello Developers! I am learning algorithms from Algorithms Design Manual Book by Skiena. There I have the following code:
#include <stdio.h>
#include <stdlib.h>
typedef int item_type;
typedef struct{
item_type item;
struct list* next;
}list;
void insert_list(list **l, item_type x){
list *p;
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
int main(){
return 0;
}
It gives me Warning when compiled:
gcc -Wall -o "test" "test.c" (in directory:
/home/akacoder/Desktop/Algorithm_Design_Manual/chapter2) test.c: In
function ‘insert_list’: test.c:15: warning: assignment from
incompatible pointer type Compilation finished successfully.
But when I rewrite this code as C++:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef int item_type;
typedef struct{
item_type item;
struct list* next;
}list;
void insert_list(list **l, item_type x){
list *p;
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
int main(){
return 0;
}
It gives the following:
g++ -Wall -o "chapter2" "chapter2.cpp" (in directory:
/home/akacoder/Desktop/Algorithm_Design_Manual/chapter2)
chapter2.cpp:15: error: conflicting declaration ‘typedef struct list
list’ chapter2.cpp:14: error: ‘struct list’ has a previous declaration
as ‘struct list’ chapter2.cpp: In function ‘void insert_list(list**,
item_type)’: chapter2.cpp: In function ‘void insert_list(list**,
item_type)’: chapter2.cpp:19: error: invalid conversion from ‘void*’
to ‘list*’
Can anyone explain why it is so? And How can I rewrite it in C++?
This is because c++ is stricter than c with respect to type conversions.
There are host of other errors in your code. Please note that just putting a c source code, renaming the file as .cpp & compiling using g++ does not make a c source code as c++.
If you are writing a program in c++ please use new & not malloc, doing so you do not need to explicitly type cast as in case of malloc.
Your problem in both cases is in the struct definition: struct list *next doesn't refer to the struct you are in the process of declaring. Try this instead:
typedef struct list {
item_type item;
struct list* next;
} list;
In addition, in C++ you must cast the void * returned by malloc to the appropriate pointer type (list *), C++ is stricter about these things. Also, BTW, in C++ you can leave off the typedef completely if you want.
The reason for the differing error messages is a difference in the languages.
In C, the compiler knows that struct list * is a pointer to a struct, so it doesn't need to complain that it doesn't actually know what a "struct list" is yet. Later, though, when you try to assign this "struct list *" from a pointer of type "list *" (the type of which is "pointer to an anonymous struct"), it complains about the mismatch.
In C++, a "struct" declaration is more or less equivalent to a "class" declaration (the major difference is in the default visibility of members). Among other things, this means that structs in C++ are more or less automatically typedefed. So when the compiler sees "struct list *next", it takes it as a forward declaration of a class named "list"; then when it finishes the statement and processes the typedef, throws an error because you're trying to typedef something to an identifier that is already (forward-)declared as something else. Then it issues further errors because it doesn't actually know what "list" might be, due to the earlier error.
C++ does not allow arbitrary pointer conversions, while C does. But since this is not considered good style, the compiler emits a warning.
Just add a cast and it will solve both messages:
p = (list*)malloc(sizeof(list));
Or if you want to be C++ only:
p = new list;
But then, you should declare constructors and such, also.
This is explained in this link.
Quote:
Gotcha for a C++ programmer using C
Structs and Enums
You have to
include the struct keyword before the name of the struct type to
declare a struct: In C++, you could do this
struct a_struct {
int x; };
a_struct struct_instance;
and have a new instance of a_struct called struct_instance. In C,
however, we have to include the struct keyword when declaring
struct_instance:
struct a_struct struct_instance;
In fact, a similar situation also holds for declaring enums: in C, you
must include the keyword enum; in C++, you don't have to. As a side
note, most C programmers get around this issue by using typedefs:
typedef struct struct_name {
/* variables */ } struct_name_t;
Now you can declare a struct with
struct_name_t struct_name_t_instance;
But there is another gotcha for C++ programmers: you must still use
the "struct struct_name" syntax to declare a struct member that is
a pointer to the struct.
typedef struct struct_name {
struct struct_name instance;
struct_name_t instance2; /* invalid! The typedef isn't defined
yet */ } struct_name_t;
You need to change this class:
typedef struct{
item_type item;
struct list* next;
}list;
to this:
struct list {
item_type item;
list* next;
};
Explanation: in the first example, you have anonymous structure, inside which struct list is forward declared. So when compiler sees typedef on the next line it finds a name collision, because typedef is not the same as struct declaration in C++.
Since what you're doing is really defining a struct and then creating an alias with the typedef I think it's more readable to do this in the C case:
typedef struct list_ {
item_type item;
struct list_* next;
} list;
Use the following code
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef int item_type;
struct list{
item_type item;
list* next;
};
void insert_list(list **l, item_type x){
list *p;
p = (list*)malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
int main(){
return 0;
}
What C only warns against, C++ is likely to consider an error.
It's a programming cultural thing. C was very forgiving in not enforcing it's typing system. C++ is still quite forgiving, but you're doing something in C that even C++ won't forgive.
When you malloc that block of memory, cast it to a pointer to a list. That will covert the address (pointer) to a pointer of the right type.
Without that cast, you could have malloc'd the size of anything, and there's no telling if it was meant to be referenced by a list pointer or some other pointer.