Trouble understanding static in header files ( inline ) - c++

I've been working with static for quite a long time but now when the header files come I'm a little confused.
The main problem is this code :
#include <iostream>
#include <string>
#include <sstream>
#include <set>
#ifndef WORD_H
#define WORD_H
#include<unordered_map>
class Word
{
private:
std::string word;
int k;
static std::unordered_map<std::string, int> x;
public:
Word(std::string word) : word(word)
{
if (x.find(word) != x.end())
x.insert({ word , 0 });
else
{
x[word]++;
}
}
std::string getWord() const
{
return x.find(this->word)->first;
}
int getCount() const
{
return x.find(this->word)->second;
}
friend bool operator<(const Word& a, const Word& b);
};
bool operator<(const Word& a, const Word& b)
{
return a.getWord() < b.getWord();
}
#endif
std::ostream& operator<<(std::ostream& out, const Word& w) {
return out << w.getWord() << " " << w.getCount();
}
void printWordCounts(const std::string& line) {
std::istringstream lineIn(line);
std::set<Word> words;
std::string wordStr;
while (lineIn >> wordStr) {
words.insert(Word(wordStr));
}
for (Word w : words) {
std::cout << w << std::endl;
}
}
int main() {
std::string line;
std::getline(std::cin, line);
printWordCounts(line);
std::cout << "---" << std::endl;
std::getline(std::cin, line);
printWordCounts(line);
return 0;
}
I know that there is a problem with the static keyword, but what exactly is it?
Also, the error is one of my favourites. Those errors between linker and STL:
Error LNK2001 unresolved external symbol "private: static class std::unordered_map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,struct std::hash<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,struct std::equal_to<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,int> > > Word::x" (?x#Word##0V?$unordered_map#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##HU?$hash#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###2#U?$equal_to#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###2#V?$allocator#U?$pair#$$CBV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##H#std###2##std##A) ConsoleApplication63 C:\Users\Ivo\source\repos\ConsoleApplication63\ConsoleApplication63\ConsoleApplication63.obj 1
I hope that someone can give me an explanation.

You have only declared the static member x. You also need to define it outside the class like this:
std::unordered_map<std::string, int> Word::x;
From c++17, you can define x inside the class definition like this:
inline static std::unordered_map<std::string, int> x;

Static variable declarations in classes are identical to declaring a global variable in a header file, except it's 'symbol' lies within the namespace of the class and therefore access to it is protected with visibility levels. This means that like global variable declarations, static class variable declarations have 'weak' linkage and a compilation unit needs to define the symbol definition, so that the linker can tie the memory associated with the variable declarations in other files to exactly one variable.
Defining the static variable is done outside the class like so:
// <variable type> <class type>::<variable name>;
std::unordered_map<std::string, int> Word::x;
Note that only one .cpp file needs to define the variable

Related

When trying to execute a from_json and to_json to a struct I created, a linker problem arises [duplicate]

This question already has answers here:
c++: class declaration and definition separated inside header causes Duplicate Symbol
(2 answers)
Closed 1 year ago.
I created a struct:
{
unsigned int id;
std::string name;
unsigned int maxPlayers;
unsigned int numOfQuestionsInGame;
unsigned int timePerQuestion;
unsigned int isActive;
} RoomData;
In my code, I have to create a vector of RoomData and then convert it into a json object (I'm using nlohmann, and unable to use any other method due to restrictions in my instructions), and to do so, i tried to create a from_json and to_json functions.
The code itself (this is the header file of the code):
#include <iostream>
#include <string>
#include <vector>
#include "LoggedUser.h"
#include "json.hpp"
namespace nh = nlohmann;
namespace rd {
typedef struct RoomData
{
unsigned int id;
std::string name;
unsigned int maxPlayers;
unsigned int numOfQuestionsInGame;
unsigned int timePerQuestion;
unsigned int isActive;
} RoomData;
void from_json(const nh::json& j, RoomData& val)
{
j.at("id").get_to(val.id);
j.at("name").get_to(val.name);
j.at("maxPlayers").get_to(val.maxPlayers);
j.at("numOfQuestionsInGame").get_to(val.numOfQuestionsInGame);
j.at("timePerQuestion").get_to(val.timePerQuestion);
j.at("isActive").get_to(val.isActive);
}
void to_json(nh::json& j, const RoomData& val)
{
j["id"] = val.id;
j["name"] = val.name;
j["maxPlayers"] = val.maxPlayers;
j["numOfQuestionsInGame"] = val.numOfQuestionsInGame;
j["timePerQuestion"] = val.timePerQuestion;
j["isActive"] = val.isActive;
}
}
class Room
{
public:
Room() = default;
Room(const rd::RoomData& data);
void addUser(LoggedUser); // adds a user to the users vector
void removeUser(LoggedUser); // removes a user from the users vector
std::vector<std::string> getAllUsers(); // return a vector of all the users
// getters
rd::RoomData getRoomData() const;
private:
rd::RoomData m_metadata; // the data of the room
std::vector<LoggedUser> m_users; // the vector of the users in the room
};
After trying to run it, a LNK2005 error arises. I know that the type I use and those functions have to be in the same namespace, did I do it wrong?
The exact error:
"void cdecl to_json(class nlohmann::basic_json<class std::map,class std::vector,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,bool,int64,unsigned __int64,double,class std::allocator,struct nlohmann::adl_serializer,class std::vector<unsigned char,class std::allocator<unsigned char> > > &,struct RoomData const &)" (?to_json##YAXAAV?$basic_json#Vmap#std##Vvector#2#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##2#_N_J_KNVallocator#2#Uadl_serializer#nlohmann##V?$vector#EV?$allocator#E#std###2##nlohmann##ABURoomData###Z) already defined in Communicator.obj
Apparently, to solve this kind of issue, all I had to do was adding "inline" at the start of the function.
Example:
inline void to_json(nh::json& j, const RoomData& val)
My reference: https://github.com/nlohmann/json/issues/542

Embedding a parser from a separate translation unit into another parser

I am trying to reuse a parser (named parser1_rule) that I have isolated in a translation unit (unit1.h/unit1.cpp), into another parser (name trace_parser). However I get a warning and an error message (reproduced and reformated below for easier reading) stating more or less (this is my interpretation) that parser1_rule have not been defined (or instantiated) for the new context trace_context_t.
Indeed, in X3, rules have two template parameters: iterators and context. I thought when mixing two rules, one had to make sure they both use the same context and iterator's types. So I paid attention to use the same context for parser1_rule and trace_parser : context_type. The same goes for the iterator, as recalled in X3: Linker Error (unresolved external symbol “parse_rule”) on nonterminal parser
But it seams this is not the way to go ? Shall I move the rule's definitions into an hpp file (which I wish I can avoid).
I created a minimal reproducible example to help understanding the issue:
EDIT: boost 1.71.0 and Visual Studio 16.8.2
unit1.h
#ifndef UNIT1_H
#define UNIT1_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
using iter_t = boost::spirit::istream_iterator;
using context_t = x3::phrase_parse_context<x3::ascii::space_type>::type;
using parser1_t = x3::rule<class p1, std::uint64_t>;
BOOST_SPIRIT_DECLARE(parser1_t);
parser1_t const & ATparser();
#endif /* UNIT1_H */
unit1.cpp
#include "unit1.h"
parser1_t const parser1 = "parser1_rule";
auto const parser1_def = x3::lexeme[x3::lit("AT") >> x3::uint_];
BOOST_SPIRIT_DEFINE(parser1);
BOOST_SPIRIT_INSTANTIATE(parser1_t, iter_t, context_t);
parser1_t const& ATparser() { return parser1; }
Source.h
#ifndef SOURCE_H
#define SOURCE_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
namespace trace {
using trace_parser_tag = struct trace_parser;
using rule_type = x3::rule<trace_parser_tag>;
BOOST_SPIRIT_DECLARE(rule_type);
}
trace::rule_type const& trace_parser();
#endif
Source.cpp
#include <iostream>
#include <fstream>
#include "unit1.h"
#include "Source.h"
namespace x3 = boost::spirit::x3;
/** reading:
Trace address: AT123434 */
namespace trace {
rule_type const tr = "trace_parser";
auto fill = [](auto& ctx) {}; /* semantic action to break automatic attribute propagation (first step) */
auto const tr_def = ("Trace address: " >> ATparser())[fill];
BOOST_SPIRIT_DEFINE(tr);
BOOST_SPIRIT_INSTANTIATE(rule_type,iter_t,context_t)
}
trace::rule_type const& trace_parser() {
return trace::tr;
}
int main(int argc, char* argv[])
{
std::string input("Trace address: AT123434");
std::ifstream i(input);
std::cout << "parsing: " << input << "\n";
boost::spirit::istream_iterator b(i >> std::noskipws);
boost::spirit::istream_iterator e = {};
bool v = x3::phrase_parse(b, e, trace_parser(), x3::ascii::space);
std::cout << "result: " << (v ? "OK" : "Failed") << "\n";
return v;
}
compilation output
1>Source.cpp
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
1>Source.obj : error LNK2019: unresolved external symbol "bool __cdecl parse_rule<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > >(struct boost::spirit::x3::rule<class p1,unsigned __int64,0>,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,unsigned __int64 &)" [...cut...] referenced in function "public: bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> >,unsigned __int64>(class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,struct boost::spirit::x3::unused_type,unsigned __int64 &)const "
Warning:
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
Error message:
unresolved external symbol:
bool __cdecl parse_rule<iterator_t,trace_context_t>(
parser1_t,
iterator_t &,
iterator_t const &,
trace_context_t const &,
unsigned __int64 &
)
referenced in function
public:
bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<
iterator_t, trace_context_t, unsigned __int64>
(
iterator_t &,
iterator_t const &,
trace_context_t const &,
struct boost::spirit::x3::unused_type,
unsigned __int64 &
)const
Assuming the following shorcuts:
using action_t = struct boost::spirit::x3::action<
struct boost::spirit::x3::sequence<
struct boost::spirit::x3::literal_string<
char const *,
struct boost::spirit::char_encoding::standard,
struct boost::spirit::x3::unused_type>,
struct boost::spirit::x3::rule<class p1,unsigned __int64,0>>,
class <lambda_bca3e58e86871d1e58f1a6062ad05fd2>>
using ctxt_t = struct boost::spirit::x3::context<
struct boost::spirit::x3::skipper_tag,
struct boost::spirit::x3::char_class<
struct boost::spirit::char_encoding::ascii,
struct boost::spirit::x3::space_tag> const ,
struct boost::spirit::x3::unused_type>>
using iterator_t = class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >
using trace_context_t = struct boost::spirit::x3::context<
struct trace::trace_parser,
action_t const ,
ctxt_t>
Move to Boost 1.74.0 solved the issue.

Runtime error when using std::bind

The following code compiles and runs successfully on OS X using Xcode 6.3.2. However, it crashes when run on Windows using VS2013.
#include <vector>
#include <string>
#include <memory>
#include <functional>
#include <iostream>
void validate(const std::string& name,
int value,
std::vector<std::string>& values)
{
std::cout << "name: " << name << " value: " << value << "\n";
}
struct Property
{
public:
Property(const std::string& name,
const std::function<void(const std::string&, int)>& validationFunction) :
m_name(name),
m_validationFunction(validationFunction)
{
}
const std::string m_name;
const std::function<void(const std::string&, int)> m_validationFunction;
};
const std::vector<std::shared_ptr<Property>> properties
{
{
std::make_shared<Property>("identifier1",
[](const std::string& name, int value)
{
validate(name, value, std::vector<std::string>{"foo"});
})
},
{
std::make_shared<Property>("identifier2",
std::bind(validate,
std::placeholders::_1,
std::placeholders::_2,
std::vector<std::string>{"bar"}))
}
};
int main()
{
properties[0]->m_validationFunction(properties[0]->m_name, 4);
properties[1]->m_validationFunction(properties[1]->m_name, 5);
return 0;
}
The reason for the crash is that the first element in properties appears to be corrupt. When I inspect the memory I see this:
properties { size=2 } std::vector<std::shared_ptr<Property>,std::allocator<std::shared_ptr<Property> > >
[size] 2 int
[capacity] 2 int
[0] shared_ptr {m_name=<Error reading characters of string.> m_validationFunction={...} } [4277075694 strong refs, 4277075693 weak refs] [{_Uses=4277075694 _Weaks=4277075694 }] std::shared_ptr<Property>
[1] shared_ptr {m_name="identifier2" m_validationFunction=bind(0x011315a5 {schema-init.exe!validate(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,int,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > &)}, (_1, _2, { size=1 })) } [1 strong ref] [make_shared] std::shared_ptr<Property>
[Raw View] 0x0115295c {schema-init.exe!std::vector<std::shared_ptr<Property>,std::allocator<std::shared_ptr<Property> > > properties} {...} std::vector<std::shared_ptr<Property>,std::allocator<std::shared_ptr<Property> > > *
If I replace std::bind with a direct call to validate as for the first element in properties then the code executes successfully.
Can someone explain what I'm doing wrong.
I noted Paul R's comment above that he successfully ran the code using VC2013 so I updated my copy of Visual Studio 2013 (update 5) and the code now runs ok. So I guess it was a compiler bug.

overloading << for my class

I'm trying to write the global function:
std::ostream& operator<<(std::ostream& out, const Str& str)
{
for(int i = 0; i < (int)str.mSize; ++i)
out << str.mBuffer[i];
return out;
}
For a custom string class. It compiles fine but when I go to link:
1>Str.obj : error LNK2005: "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Str const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABVStr###Z) already defined in Main.obj
1>C:\Users\Ron\Documents\Visual Studio 2010\Projects\App\Debug\App.exe : fatal error LNK1169: one or more multiply defined symbols found
How could multiple definitions for this exist? I just created the class Str.
I think you have defined twice in Main.cpp and Str.cpp, or may be .h files.
Write a str.h files which include the declaration of the Str class:
//str.h
class Str {
// your class stuff
friend std::ostream& operator<<(std::ostream& out, const Str& str);
};
then in str.cpp:
//str.cpp
#include "str.h"
std::ostream& operator<<(std::ostream& out, const Str& str) {
for(int i = 0; i < (int)str.mSize; ++i)
out << str.mBuffer[i];
return out;
}
Then you can use the function in you main.cpp.
If you define a function in a header file and include it twice, you'll get a multiple definition error, which you have.
To remedy this, declare the function in the header with a prototype and define it in a .cpp file.
Alternately, if you're trying to make a header only library, you could do
class Str {
// your class stuff
friend std::ostream& operator<<(std::ostream& out, const Str& str) {
for(int i = 0; i < (int)str.mSize; ++i)
out << str.mBuffer[i];
return out;
}
};
Did you put this in a header file?
The right way to do it is to declare it in the header file and put the code in a source file.

Weird linker error with static std::map

Why do I get linker error when I try to compile this in Visual Studio 2008
#include <stdafx.h>
#include <iostream>
#include <map>
#include <string>
class MyClass
{
public:
MyClass () { };
virtual ~MyClass() {};
static std::string niceString (std::map<int, int> mappp) { _myMap = mappp; return "nice string"; };
private:
static std::map<int, int> getMap ( ) { return _myMap; };
static std::map<int, int> _myMap;
};
int main(){
std::map<int, int> mappp;
mappp[1] = 1;
std::cout << MyClass::niceString(mappp);
}
error is:
Error 1 error LNK2001: unresolved external symbol "private: static class std::map<int,int,struct std::less<int>,class std::allocator<struct std::pair<int const ,int> > > MyClass::_myMap" (?_myMap#MyClass##0V?$map#HHU?$less#H#std##V?$allocator#U?$pair#$$CBHH#std###2##std##A) test22.obj test22
You've declared the static member _myMap, but not defined it. Add this line just above int main():
std::map<int, int> MyClass::_myMap;
Think of it like a function that has been declared but not defined in any .cpp file - you get a linker error if you use it.