Static1.hpp
#include <string>
class Static1
{
public:
static const std::string my_string;
};
Static1.cpp
#include "Static1.hpp"
const std::string Static1::my_string = "aaa";
Static2.hpp
#include <string>
class Static2
{
public:
static const std::string my_string;
};
Static2.cpp
#include "Static2.hpp"
const std::string Static2::my_string = Static1::my_string;
main.cpp
#include "Static2.hpp"
#include <iostream>
int main(argc int, char** argv)
{
cout << to_string(Static2::my_string == "aaa") << endl;
return 0;
}
If I put add_executable(printMyString main.cpp Static2.cpp Static1.cpp) in my CMakeLists.txt, I get
0
while add_executable(printMyString main.cpp Static2.cpp Static1.cpp) gives me the expected behavior of
1
To make my code easier to maintain (so that I don't need to keep track of the order I list my source files), is there any way I can ensure that I get the behavior where Static2::my_string == "aaa"?
You are experiencing effects of a static initialization order fiasco.
The usual work-around is to substitute your static variables with functions that have a static variable in the scope, initialize, and return it.
Here is how it could be done for your example: Live Example (order1)
Live Example (order2)
class Static1
{
public:
static std::string my_string();
};
...
std::string Static1::my_string()
{
static const std::string my_string = "aaa";
return my_string;
}
...
class Static2
{
public:
static std::string my_string();
};
...
std::string Static2::my_string()
{
static const std::string my_string = Static1::my_string();
return my_string;
}
...
std::cout << std::to_string(Static2::my_string() == "aaa") << std::endl;
Related
I want to be able to pass a string literal to a class instance and also check at compile time for certain conditions on the string literal. But I want the string checking to be done by the class somehow. I have a sample code with roughly what I'm trying to achieve:
#include <type_traits>
#include <string>
#include <string_view>
class TestString
{
public:
constexpr bool TestStringCondition(const char* name) noexcept
{
return std::string_view(name).find('a') != std::string_view::npos; //random condition
}
constexpr TestString(const char* name) noexcept:
m_name(name)
{
static_assert(TestStringCondition(name), "error message");
}
const char* m_name = nullptr;
};
int main()
{
static constexpr const char* const name = {"foo"};
static const TestString testString { name };
}
I tried various options (templates, char_traits, etc.) but keep getting compiler error "static_assert expression is not an integral constant expression". It seems to not be happy with the stringliteral passed as a parameter as I can do the assert check outside the class. I cannot use any c++20 features yet and I want a way avoiding Boost. Does anyone know a way?
The following works but I am unsure if it is what you want:
#include <type_traits>
#include <string_view>
template<const char *const t_name>
class TestString {
public:
static constexpr bool TestStringCondition(const char *name) noexcept {
return std::string_view(name).find('a') != std::string_view::npos; // random condition
}
constexpr TestString() noexcept {
static_assert(TestStringCondition(t_name));
}
};
constexpr char okay[] = "okay"; // array, so it is a static object with linkage
int main() {
static const TestString<okay> testString{};
}
I'm trying to create a class that stores pointers to member functions of other classes and that can be executed from a text command (like a game console).
I did something functional, based on an example found here, that stores members with string-like input. Below is my implementation.
file: Command.hpp
#include <string>
#include <functional>
#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
class Command
{
public:
Command();
virtual ~Command();
void RegisterCommand(string command, function<void(const string&)> fun);
void Run(const string& command, const string& arg);
private:
unordered_map<string, function<void(const string&)>> functions;
};
file: Command.cpp
Command::Command()
{
}
Command::~Command()
{
}
void Command::RegisterCommand(string command, function<void(const string&)> fun)
{
functions[command] = fun;
}
void Command::Run(const string& command, const string& arg)
{
functions[command](arg);
}
file: main.cpp
#include "Command.hpp"
// function to register
void xyz_fun(const string& commandLine)
{
cout << "console output: " << commandLine << endl;
}
int main(int argc, char* argv[])
{
Command m_Cmd;
// Register function
m_Cmd.RegisterCommand("xyz_fun", xyz_fun);
// Run registered function
m_Cmd.Run("xyz_fun", "hello world.");
return EXIT_SUCCESS;
}
My question is how to implement a generic class to store members with unknown input arguments (Booleans, integers, doubles, strings, etc.).
For example, I could do:
m_Cmd.RegisterCommand("xyz_fun2", xyz_function2);
and call
m_Cmd.Run("xyz_fun2", false)
which has a boolean argument instead of a string.
Thanks in advance for your attention and any help is welcome.
Instead of
unordered_map<string, function<void(const string&)>> functions;
you could do
union acceptable_types { int i; char c; bool b; std::string* s; ... };
unordered_map<string, function<void(acceptable_types)>> functions;
Then when calling functions, just place the value wanted by the function into a variable of type acceptable_types.
If a function is wants to use a specific value, it should just use a specific member of the acceptable_types union.
Here's an example:
#include "Command.hpp"
void
my_bool_func (acceptable_types union_param)
{
bool bool_var = union_param.b;
// ...
// Use bool_var
// ...
}
void
my_string_func (acceptable_types union_param)
{
std::string string_var = *(union_param.s);
// ...
// Use string_var
// ...
}
int
main(int argc, char* argv[])
{
Command my_command;
acceptable_types union_var;
my_command.RegisterCommand("my_bool_func", my_bool_func);
my_command.RegisterCommand("my_string_func", my_string_func);
union_var.b = true;
my_command.Run("my_bool_func", union_var);
*(union_var.s) = "hello world.";
my_command.Run("my_string_func", union_var);
return 0;
}
I would like to use a string before .getName()
Enemy Troll(Troll, 250, 30);
string enemyName;
enemyName = Troll;
enemyName.getName(); //this is causing the error... "No member named 'setHP' in 'std::__1::basic_string<char>'"
I want to be able to get the same results as using Troll.getName(); but instead use a string.
There is no built in way in C++ to use a string to look up a variable of the same name in C++.
What you have to do is create the appropriate data structure for yourself. One way to do that would be to use a map.
#include <map>
std::map<std::string, Enemy> my_map;
...
Enemy trump("Trump", 250, 30);
my_map["Trump"] = trump;
...
std::string name = ...;
Enemy some_enemy = my_map[name];
You can store all the instances by name as a static data member in a map for example. But there should be better ways to do it depending on the complete design of your program. But since you didn't provide all the context I'm just going to show a generic example. With some issues like non thread safety, missing null checks, not dealing with duplicates, etc.
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Enemy{
public:
std::string m_name;
int m_hp;
int m_dmg;
static std::map<std::string,Enemy*> s_instances;
Enemy(const std::string& name, int hp, int dmg)
: m_name(name),
m_hp(hp),
m_dmg(dmg)
{
s_instances[name] = this;
}
~Enemy()
{
s_instances.erase(m_name);
}
const std::string& getName() const
{
return m_name;
}
static Enemy* getInstanceByName(const std::string& name)
{
Enemy* result = nullptr;
auto iter = s_instances.find(name);
if(iter!=s_instances.end()) result = iter->second;
return result;
}
};
std::map<std::string,Enemy*> Enemy::s_instances;
void doStuff()
{
Enemy* instance = Enemy::getInstanceByName("Ork");
std::cout << instance->getName();
}
int main() {
Enemy ork("Ork",300,20);
doStuff();
return 0;
}
I am using a static method to initialise the const fields of a class. The static method uses some const variables that are stored in a separate header file. Primitive types are correctly being passed to the static method, but the std::strings are being passed empty. I cannot understand why this is.
After doing some searching I have stumbled upon something called the static initialiser fiasco, but I'm having trouble wrapping my head around it, and can't work out if it is to blame. As the the object is in global scope, is the problem that it is being 'setup' before the std::string class has been 'setup'?
I have tried to replicate a minimal example below:
// File: settings.hpp
#include <string>
const std::string TERMINAL_STRING "Printing to the terminal";
const std::string FILE_STRING "Printing to a file";
// File: printer.hpp
#include <string>
#include <iostream>
class Printer
{
private:
const std::string welcomeMessage;
static std::string initWelcomeMessage(std::ostream&);
public:
Printer(std::ostream&);
}
extern Printer::print;
// File: printer.cpp
#include "settings.hpp"
std::string Printer::initWelcomeMessage(std::ostream &outStream)
{
if (&outStream == &std::cout)
{
return (TERMINAL_STRING);
}
else
{
return (FILE_STRING);
}
}
Printer::Printer(std::ostream &outStream) :
message(initWelcomeMessage(outStream)
{
outStream << welcomeMessage << std::endl;
return;
}
// File: main.cpp
#include "printer.hpp"
printer print(std::cout);
int main()
{
return (0);
}
Thanks very much!
As the the object is in global scope, is the problem that it is being 'setup' before the std::string class has been 'setup'?
Yes.
Have your strings be function-statics, returned by reference from some function, instead.
This is the traditional fix for the static initialisation order fiasco.
#include <iostream>
#include <cstring>
#include <QString>
using namespace std;
class A {
public:
static const int i = 9;
static const int PI = 1.3;
static const char ch = 's';
static const string str = "hello world"; // <--- error
static const QString str2 = "hello world"; // <--- error
};
int main(int argc, char **argv) {
cout << "Hello world" << endl;
return 0 ;
}
As the code gives everything, how can I init a string.
Non-integral type members (that includes string and your user-defined types), need to be initialized outside the class definition, in a single implementation file (.cc or .cpp usually).
In your case, since you didn't separate the class definition in a header, you can initialize the statics right after your class:
class A {
public:
static const int i = 9;
static const int PI = 1.3;
static const char ch = 's';
static const string str;
static const QString str2;
};
const string A::str = "hello world";
const QString A::str2 = "hello world";
EDIT: Besides this, as Nawaz pointed out, the header file that defines string is <string>, not <cstring>.
First thing first. You've not included <string>. So do that first:
#include <string>
std::string is defined in <string>, not in <cstring> as you probably might think.
After that in C++03, initialization of the non-integral static member of a class, must be outside the class.
In C++11, your code will compile if you only include <string>. No need to define the static member outside the class.