Initializing string array in a class function - c++

I tried to initialize an array of string in class as following:
class Haab{
string str[];
Haab(){
str[] = {"abc", "abd", "abe"};
}
};
But the Devc++ 5.6.1 reports a warning:
[Warning] extended initializer lists only available with -std=c++11 or -std=gnu++11 [enabled by default]
Is this way of initializing arrays in class illegal? If so, how to properly initialize the array? Thank you.

The given code,
class Haab{
string str[];
Haab(){
str[] = {"abc", "abd", "abe"};
}
};
is invalid in a number of ways:
string str[]; declares a member array of unknown size. Can't do that.
In str[] = {"abc", "abd", "abe"};, the expression str[] uses the [] indexing operator without specifying the index.
If that parsed, then the = would denote assignment of a single string.
Here's one C++03 way to do things:
#include <string>
#include <vector>
namespace qwe {
using std::string;
using std::vector;
class Haab
{
private:
vector<string> str_;
public:
Haab()
{
static char const* const data[] = {"abc", "abd", "abe"};
for( int i = 0; i < 3; ++i )
{
str_.push_back( data[i] );
}
}
};
} // namespace qwe
There are also other C++03 ways, all of them ugly (as the above).
In C++11 and later it can be done with more elegant & simple notation;
#include <string>
#include <vector>
namespace qwe {
using std::string;
using std::vector;
class Haab
{
private:
vector<string> str_;
public:
Haab()
: str_{ "abc", "abd", "abe"}
{}
};
} // namespace qwe
but this does still not compile with Visual C++ 13.0 (it does compile with MinGW g++ 4.9.1).

Related

Why I am fail my convert string to a C-string trying this way?

My code in VS2019 is not working.
In the last line of code compiler throws an error.
#include <iostream>
#include <string>
using namespace std;
struct struct1
{
string name;
};
void main()
{
struct1* obj1 = new struct1();
obj1->name = "Hello";
// compiler says 'initializing': cannot convert from 'const _Elem *' to 'char [25]'
char str[25] = (obj1->name).c_str();
}
c_str() returns a pointer to the start of the string's character data. You'll need to copy the characters into your array using something like strncpy().
there is a lot of ways to do this
but first you should change the manner of char array initialization because you made it wrongly.
this is the same program but working
#include <iostream>
using namespace std;
struct struct1
{
string name;
};
int main()
{
struct1* obj1 = new struct1();
obj1->name = "Hello";
char str[25] = "";
memcpy(&str,obj1->name.c_str(),obj1->name.size());
cout << str << endl;
}

Autocasting C++ char array as string

Let's say I have a String class that can be constructed with a char array pointer. Is there any crazy way, through some magical operator overload, free function, or preprocessor macro to make Python-like syntax work, autocasting a char array literal to a String? To make this compile:
String a = "Foo".substr(1);
I suppose a wild pre-compile sed statement would do it, but something within the abilities of clang would be preferred.
For C++11 and beyond
#include <iostream>
#include <string>
int main() {
using namespace std::string_literals;
auto a = "foo"s.substr(1);
}
If you wanted to write this for your own String class then the way to get the same behavior would be to roll your own user defined string literal, and then do the same
#include <cstddef>
class Str {
public:
explicit Str(const char*) {}
Str substr(int) { return *this; }
};
Str operator"" _s (const char* input, std::size_t) {
return Str{input};
}
int main() {
auto s = "something"_s.substr(1);
}

Enum in a class with strings

I'm trying to implement a class (C++) with an enum (with the permitted parameters). I got a working solution, but if I try to extend the functionality I get stuck.
Header data_location.hpp
class DataLocation
{
private:
public:
enum Params { model, period };
std::string getParamString(Params p);
};
Program data_location.cpp
string DataLocation::getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
The array ParamsStrings should be generally available in the class, because I need a second method (with inverse function) returning the enum value given a string.
If I try to define the array in the header I get the error:
in-class initialization of static data member ‘const char* DataLocation::ParamsStrings []’ of incomplete type
Why is the type incomplete? The compiler is for sure able to counts the strings in the array, isn't it?
In case there is no way to get my code working, is there an other way? With 1) no XML; 2) no double definition of the strings; 3) not outside the class; 4) no in code programmed mapping.
In class (header) use keyword static and initialize it outside (.cpp) without the static keyword:
class DataLocation {
public:
enum Params { model, period };
string getParamString(Params p);
static const char* ParamsStrings[];
// ^^^^^^
};
const char* DataLocation::ParamsStrings[] = {"MODEL", "BLLBLA"};
//^^^^^^^^^^^^^^^^^^^^^^^^
The code you have posted is perfectly fine.
Here's the proof:
#include <iostream>
#include <string>
struct DataLocation
{
enum Params { model, period };
std::string getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
};
int main()
{
auto a = DataLocation();
std::cout << a.getParamString(DataLocation::model) << std::endl;
return 0;
}
The error message you are getting is not to do with definition of a static data member in an inline function - that's allowed.
There's something else you're not showing us.
The main issue in my question (the second part) was that if I split the class in .hpp and .cpp the definition of the array (I mixed *char and string) has also to be split:
// data_location.hpp
class DataLocation {
static const char * ParamsStrings[];
}
// data_location.cpp
const char * ParamsStrings[] = {"MODEL", "PERIOD"};
At the end I introduced a consistency check to be sure that the number of values in enum growths as the number of strings. Because the array in C++ is somehow limited I had to go for a std::vector (to get the size).
Code for data_location.hpp
#ifndef DATA_LOCATION_HPP_
#define DATA_LOCATION_HPP_
#include <string>
#include "utils/dictionary.hpp"
extern const char* ENV_DATA_ROOT;
struct EDataLocationInconsistency : std::runtime_error
{
using std::runtime_error::runtime_error;
};
struct EDataLocationNotValidParam : std::runtime_error
{
using std::runtime_error::runtime_error;
};
class DataLocation
{
private:
std::string mRootLocation;
static const std::vector<std::string> msParamsStrings;
static bool msConsistenceCheckDone;
public:
DataLocation();
std::string getRootLocation();
std::string getLocation(Dictionary params);
enum Params { model, period, LAST_PARAM};
std::string Param2String(Params p);
Params String2Param(std::string p);
};
#endif
Code for data_location.cpp
#include "data_location.hpp"
#include <string>
#include <cstdlib>
using namespace std;
const char* ENV_DATA_ROOT = "DATA_ROOT";
bool DataLocation::msConsistenceCheckDone = false;
DataLocation::DataLocation() {
mRootLocation = std::getenv(ENV_DATA_ROOT);
if (not msConsistenceCheckDone) {
msConsistenceCheckDone = true;
if (LAST_PARAM+1 != msParamsStrings.size()) {
throw(EDataLocationInconsistency("DataLocation: Check Params and msParamsStrings"));
}
}
}
string DataLocation::getRootLocation() {
return mRootLocation;
}
string DataLocation::getLocation(Dictionary params) {
// to do
return "";
}
const vector<string> DataLocation::msParamsStrings = { "MODEL", "PERIOD", ""};
string DataLocation::Param2String(Params p) {
if (p>=msParamsStrings.size()) {
throw(EDataLocationNotValidParam("Parameter not found"));
}
return msParamsStrings[p];
}
DataLocation::Params DataLocation::String2Param(string p) {
for (int i = 0; i < msParamsStrings.size(); i++) {
if (p == msParamsStrings[i])
return (Params)i;
}
throw(EDataLocationNotValidParam("Parameter not found"));
}
And also a unit test:
#include <boost/test/unit_test.hpp>
#include "data_location.hpp"
#include <string>
using namespace std;
BOOST_AUTO_TEST_SUITE( data_location )
BOOST_AUTO_TEST_CASE(data_location_1) {
DataLocation dl;
auto s = dl.getRootLocation();
BOOST_CHECK_EQUAL(s, "/home/tc/data/forex" );
BOOST_CHECK_EQUAL(dl.Param2String(DataLocation::period),"PERIOD");
BOOST_CHECK_EQUAL(dl.String2Param("PERIOD"),DataLocation::period);
BOOST_CHECK_THROW(dl.String2Param("SOMETHING"), EDataLocationNotValidParam);
BOOST_CHECK_THROW(dl.Param2String((DataLocation::Params)100), EDataLocationNotValidParam);
}
BOOST_AUTO_TEST_SUITE_END()
C++ is very picky about what it will let you initialize inside of a class definition; there are some particularly non-intuitive rules surrounding static members. It all has to do with the ODR, and why all the rules are the way they are is not especially important.
To cut to the chase, making your array a static constexpr const member should shut the compiler up. With the C++11 standard, the restrictions were relaxed a bit, and one of the new stipulations was that static constexpr members can be initialized inline. This is perfect for your application, since the strings in your array are compile-time constants.
The recent g++ compiler which support C++0x or later compiles thus code. Pure C compile compiles, too. Because strings in initialization like {"MODEL", "PERIOD"}; implemented as const char * pointer to the char array.

Cannot declare array of strings as class member

I could not declare an array of strings in my class. Below my class definition:
class myclass{
public:
int ima,imb,imc;
string luci_semaf[2]={"Rosso","Giallo","Verde"};
};
and my main file
#include <iostream>
#include <fstream>
#include "string.h"
#include <string>
using namespace std;
#include "mylib.h"
int main() {
return 0;
}
Why do I get the following warnings / error?
You have two problems: The first is that you can't initialize the array inline like that, you have to use a constructor initializer list. The second problem is that you attempt to initialize an array of two elements with three elements.
To initialize it do e.g.
class myclass{
public:
int ima,imb,imc;
std::array<std::string, 3> luci_semaf;
// Without C++11 support needed for `std::array`, use
// std::string luci_semaf[3];
// If the size might change during runtime use `std::vector` instead
myclass()
: ima(0), imb(0), imc(0), luci_semaf{{"Rosso","Giallo","Verde"}}
{}
};
You can not initialize data member.
You can write like this:
class myclass{
public:
myclass() {
luci_semaf[0] = "Rosso";
luci_semaf[1] = "Giallo";
luci_semaf[2] = "Verde";
}
private:
int ima,imb,imc;
string luci_semaf[3];
};
You can assign the values of the array in the Сonstructor
You're declaring an array of size 2 but providing 3 strings!
Try storing the elements in vector of strings, in c++ vectors are used more often.
class myclass{
public:
int ima,imb,imc;
std::vector<std::string> strings;
myclass() {
strings.push_back("blabla");
}
};

How to set an object property to a previously initialized Array in C++

I would like to take a previously initialized array of objects and be able to set that to a class variable.
I don't have a lot of experience with pointers or great coding style.
This is a snippet of the code that I'm working on which isolates the problem:
#include<cstdlib>
#include<iostream>
using namespace std;
class GameBoard {
string players[];
int total_players;
public:
GameBoard (string given_players[]) {
players = given_players;
total_players = sizeof(given_players)/sizeof(*given_players);
}
};
int main () {
string players[] = {
"Jack",
"Jill"
};
GameBoard gb(players);
return 0;
}
Currently, this code out puts the error:
In constructor 'GameBoard::GameBoard(std::string*)':
[Error] incompatible types in assignment of 'std::string* {aka std::basic_string<char>*}' to 'std::string* [0] {aka std::basic_string<char>* [0]}'
Better way of doing this
#include <vector>
#include <string>
class GameBoard {
std::vector<std::string> players;
int total_players;
public:
GameBoard (const std::vector<std::string> & p_players):
players(p_players),
total_players(p_players.size())
{
}
};
then
int main()
{
std::vector<std::string> players{"jill", "bill"}; //if C++11 is not available you can use push_back()
GameBoard b{players};
return 0;
}