In function undefined reference c++ - c++

I get a strange error all the time.
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:
In function _start: >(.text+0x20): undefined reference to main
/tmp/cc4ZqKzy.o:
In function `Sep::Building::Building(Sep::Field::FieldType, >std::__cxx11::basic_string, >std::allocator >, char, bool, bool, unsigned int, unsigned int):
Building.cpp:(.text+0x3c): undefined reference to Sep::Field::Field()
collect2:
error: ld returned 1 exit status
I read a lot with this problem but none had the same. I included all the headers and also added ifndef guards.
main.cpp:
#include "Field.h"
#include "Building.h"
namespace Sep
{
just some returns...
}
int main(int argc, char *argv[])
{
Sep::Building Haus(Sep::Field::FieldType::HOME,"HOME", 'H', true, true, 100, 100);
std::cout << "HAUS ABREV:" << Haus.getAbbrevationOnField() << '\n';
}
Field.h
#include <cstring>
#include <string>
#include <iostream>
#include <memory>
#ifndef FIELD_H
#define FIELD_H
namespace Sep
{
//----------------------------------------------------------------------------
// Field class, containing all needed information to create a Field object
//
class Field
{
public :
enum FieldType \
{GRASS, WATER, OBSTACLE, STREET, HOME, MARKET, CLINIC, TOWNHALL};
private:
FieldType type_;
std::string name_;
char abbrevation_;
bool buildable_;
bool destroyable_;
unsigned int build_cost_;
unsigned int destroy_cost_;
public:
//------------------------------------------------------------------------
// Field constructors & destructor
//
Field();
Field(FieldType type);
~Field() noexcept;
//------------------------------------------------------------------------
//getters
//
Field::FieldType getFieldType() const { return type_; };
const char getAbbrevationOnField() const { return abbrevation_; };
//------------------------------------------------------------------------
//setters
//
static std::string getName(FieldType type);
FieldType getType() const;//steht oben in getFiel3dType Z55
void setType(FieldType type){type_ = type;};
void setName(std::string name){name_ = name;};
void setAbbrevation(char abbrev){abbrevation_ = abbrev;};
void setBuildable(bool buildable){buildable_ = buildable;};
void setDestroyable(bool destroyable){destroyable_ = destroyable;};
void setBuildCost(int b_cost){build_cost_ = b_cost;};
void setDestroyCost(int d_cost){destroy_cost_ = d_cost;};
};
}
#endif //FIELD.H
Field.cpp
#include "Field.h"
#include <cstring>
#include <string>
#include <iostream>
#include <memory>
using Sep::Field;
//------------------------------------------------------------------------------
// Setter of the private FieldType type_ to the given param
//
// #param the type of field to get set
//
Field::Field(FieldType type)
{
type_ = type;
};
Field::~Field(){};
//------------------------------------------------------------------------------
// Checks the type of a given field, returns the name of type as string
//
// #param type, the type of the field to check
//
// #return string the name of the type of the checked field
//
std::string Field::getName(FieldType type)
{
switch (type)
{
case GRASS:
return std::string("Grass");
case WATER:
return std::string("Water");
case OBSTACLE:
return std::string("Obstacle");
case STREET:
return std::string("Street");
case HOME:
return std::string("Home");
case MARKET:
return std::string("Market");
case CLINIC:
return std::string("Clinic");
case TOWNHALL:
return std::string("Town Hall");
default:
return std::string("Unknown Field");
}
};
//------------------------------------------------------------------------------
// getters
//
// Getter from the private FieldType type_
//
// #param none
//
// #return the type of type_ as FieldType
//
Field::FieldType Field::getType() const
{
return type_;
};
Building.h
#ifndef BUILDING_H
#define BUILDING_H
#include "Field.h"
namespace Sep
{
class Building : public Field
{
private:
public:
Building(FieldType type, const std::string name, const char abbrevation, \
const bool buildable, const bool destroyable,\
const unsigned int b_cost, const unsigned int d_cost);
~Building();
};
}
#endif //BUILDING_H
Building.cpp
#include "Building.h"
#include "Field.h"
Sep::Building::Building(FieldType type, const std::string name, \
const char abbrevation, \
const bool buildable, const bool destroyable,\
const unsigned int b_cost, const unsigned int d_cost)
{
Sep::Field::setType(type);
Sep::Field::setName(name);
Sep::Field::setAbbrevation(abbrevation);
Sep::Field::setBuildable(buildable);
Sep::Field::setDestroyable(destroyable);
Sep::Field::setBuildCost(b_cost);
Sep::Field::setDestroyCost(d_cost);
};
Sep::Building::~Building(){};
Has anyone a idea? Cause I get this error often in this project but in other classes.
The strange thing is that it seems like, that the program compiles correctly but on the start I get this collect2: error: ld returned 1 exit status.
Thx

Field.cpp need to be changed, if don't want to used Field() constructor just put the definition of Field() constructor empty.
For examples:
Field.cpp
#include "Field.h"
#include <cstring>
#include <string>
#include <iostream>
#include <memory>
using Sep::Field;
//------------------------------------------------------------------------------
// Setter of the private FieldType type_ to the given param
//
// #param the type of field to get set
//
Field::Field(){
//empty constructor or can initialize type_ to default value.
}
Field::Field(FieldType type)
{
type_ = type;
};
Field::~Field(){};
//------------------------------------------------------------------------------
// Checks the type of a given field, returns the name of type as string
//
// #param type, the type of the field to check
//
// #return string the name of the type of the checked field
//
std::string Field::getName(FieldType type)
{
switch (type)
{
case GRASS:
return std::string("Grass");
case WATER:
return std::string("Water");
case OBSTACLE:
return std::string("Obstacle");
case STREET:
return std::string("Street");
case HOME:
return std::string("Home");
case MARKET:
return std::string("Market");
case CLINIC:
return std::string("Clinic");
case TOWNHALL:
return std::string("Town Hall");
default:
return std::string("Unknown Field");
}
};
//------------------------------------------------------------------------------
// getters
//
// Getter from the private FieldType type_
//
// #param none
//
// #return the type of type_ as FieldType
//
Field::FieldType Field::getType() const
{
return type_;
};

When you are trying to construct a Building, the Building::Building(...) constructor implicitly calls its base class constructor Field::Field() (since you did not specify which Field constructor you want). You promised in Field.h that such a constructor exists somewhere (which is why the compiler never complains), but you never define it. When the linker then tries to link the functions you declared with the functions that the compiler emitted, it notices that this constructor is missing and complains.
This is what the error messages are trying to tell you:
undefined reference to 'Sep::Field::Field()' -> The Field::Field() constructor is not defined anywhere.
In function Sep::Building::Building(...) -> It is trying to call the Field constructor in the shown Building constructor.
The simplest fix is to write Field() = default; so the compiler automatically generates the default constructor.
Edit: If you want to use the Field::Field(FieldType) constructor, this is how you would do that:
Building::Building(FieldType fieldType, /* etc */)
: Field(fieldType)
{
// etc.
}
You could also add a constructor to the Field class that takes all these arguments that you are trying to pass:
Field::Field(FieldType fieldType, std::string name, char abbrevation, /* etc. */)
: type_(fieldType), name_(name), abbrevation_(abbreviation), /* etc. */
{
}
And thus:
Building::Building(FieldType type, const std::string name, const char abbrevation, /* etc. */)
: Field(type, name, abbreviation, /* etc. */)
{
}
Even better, you can just "reuse" the long Field constructor for Building
class Building : public Field
{
public:
using Field::Field;
// ...
}

Related

Static member declaration in Parametrized polymorphism

I have gender class with Male and Female as my parametric types of class
I am using following hierarchy:
#ifndef __GENDER_H
#define __GENDER_H
#include <string>
using namespace std;
// Forward declaration of templatized class
template<typename T>
class GenderTypes; // Generic Gender type to generate specific genders
// Generic gender type
class Gender { // Abstract Base Class
const string& name_; // Name of the Gender
struct MaleType {};
struct FemaleType {};
protected:
Gender(const string& name) : name_(name) {}
virtual ~Gender() { }
public:
const string& GetName() const { return name_; }
bool IsMale(const Gender&); // Checking and matching gender
// Enumerated types - the target sub-types
typedef GenderTypes<MaleType> Male;
typedef GenderTypes<FemaleType> Female;
};
// Specific gender types
template<typename T>
class GenderTypes : public Gender {
static const string sName;
GenderTypes(const string& name = GenderTypes<T>::sName) : Gender(name) { }
~GenderTypes() { }
public:
// Singleton object - placeholder for the respective type
static const GenderTypes<T>& Type() {
static const GenderTypes<T> theObject; // May be non-const for changeable behavior
return theObject;
}
};
inline bool Gender::IsMale(const Gender& g) { return &g == &Gender::Male::Type(); }
#endif
And declaring the static member name_ as follows:
#include <string>
using namespace std;
#include "../inc/gender.h"
// Names defined as static constants
const string Gender::Male::sName = "Male";
const string Gender::Female::sName = "Female";
This kind of hierarchy is fine . then why compiler gives this error:
gender.cpp:5:14: error: specializing member ‘GenderTypes<Gender::MaleType>::sName’ requires ‘template<>’ syntax
5 | const string Gender::Male::sName = "Male";
how should i initialize this static datas?
I am using VS CODE editor and Ubuntu 20.04
With this small change in your .cpp it compiles (and works) fine on my machine :
template<>
const string Gender::Male::sName = "Male";
template<>
const string Gender::Female::sName = "Female";
And indeed in your header you should use
#ifndef GENDER_H
#define GENDER_H
[...]
#endif
OR
#pragma once
[...]

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.

Namespaces, types and the using directive-in header file same type is recognized as field and function return value types but not as parameter types

For a simple game, I have the following classes:
// color.h
#ifndef COLOR_H
#define COLOR_H
#include "ns.h"
BEGIN_NS
enum class color {
white,
black
};
END_NS
#endif
and
// position.h
#ifndef POSITION_H
#define POSITION_H
#include <string>
#include "ns.h"
BEGIN_NS
struct position {
int rank, file; // The rank and file
public:
std::string code() const;
bool valid() const {
return rank >= 0 && rank < ranks && file >= 0 && file < files;
}
bool at(int r, int f) const { return rank == r && file == f; }
bool at(const position &p) const { return rank == p.rank && file == p.file; }
public:
static position from_code(std::string code);
};
END_NS
#endif
and, finally
#ifndef PIECE_H
#define PIECE_H
#include <string>
#include "color.h"
#include "position.h"
BEGIN_NS
class board;
class piece {
protected:
piece(const std::string& type, color c, const position &start_pos);
const color _color; // The color of the piece
const position _start_pos; // The initial starting position of this piece
position _pos; // The current position of the piece
int _times_moved; // The number of times the piece was moved
bool _captured; // Defines whether the piece has been captured
const std::string _type; // Defines the type of piece
public:
const position& start() const { return _start_pos; }
const position& position() const { return _pos; }
color color() const { return _color; }
bool captured() const { return _captured; }
int moved() const { return _times_moved; }
bool enemy_of(const piece* p) const { return p && p->color() != _color; }
bool ally_of(const piece* p) const { return p && p->color() == _color; }
void capture() { _captured = true; }
virtual piece* eval(const board* board, const position &pos) const = 0;
};
END_NS
#endif
Also, the namespace macros are defined in ns.h:
#define BEGIN_NS namespace chess_game {
#define END_NS }
The problem is with the position structure usage in my piece.h file, specifically at the virtual piece* eval(...) function. The compiler cannot resolve position as a valid type, but it does not complain about position being used as a constructor arg, as two of the field types and as a return type to the start() and position() functions. Specifically, the compiler says:
IntelliSense function "chess_game::piece::position" is not a type name
C4430: missing type specifier - int assumed. Note C++ does not support default int
C2143: syntax error: missing ',' before '&'
The position parameter type in the eval function prototype is underlined, but none of the other usages of the type are underlined. If I fully qualify just that instance of position with my namespace using scope resolution, then the error goes away. If I remove just the eval function from the class, the error goes away. Why would it require the type to be fully qualified in the function parameter signature and not anywhere else in the class? Qualifying the parameter type with the namespace isn't a big deal, I just wish to know why I have to and what the problem is...
Visual Studio 2013 C++ compiler
Thanks for the assistance.
class piece {
// ...
const position& position() const { return _pos; }
// ...
The member function chess_game::piece::position() const hides the type chess_game::position() in the scope of piece. After that member function has been declared, you can no longer use just position to refer to the class.
Avoid using the same name for a type and a function.

No matching constructor for initialization of

I’ve seen similar questions on StackOverflow, but none of them seems to apply to me.
Here is my code:
Option.cpp
#include "Option.h"
Option::Option(string valueName, string description, OptionType type){
this->valueName = valueName;
this->description = description;
this->type = type;
};
Option.h
#include <iostream>
using namespace std;
enum OptionType { FLAG, REQUIRED, NORMAL };
class Option {
string valueName, description, value;
OptionType type;
public:
Option(string valueName, string description, OptionType type);
void setValue(string value) {
this->value = value;
};
string getValueName() {
return this->valueName;
};
string getDescription() {
return this->description;
};
OptionType getType() {
return this->type;
};
};
Options.cpp
#include "Options.h"
using namespace std;
Options::Options(int _argc, const char * _argv[]) : argv(_argv) {
this->argc = _argc;
}
Options::~Options() {
options.~unordered_map();
}
void Options::printHelp() {
for (auto &i : options) {
cout << i.first << '\t' << i.second.getDescription() << '\n';
}
}
void Options::addFlag(string flagName, string description) {
}
void Options::addOption(string optionName, string valueName, string description, OptionType type) {
Option option(valueName, description, type);
options[optionName]=option;
}
void Options::addOptionAlias(string aliasName, string optionName) {
}
Options.h
#include <iostream>
#include <unordered_map>
#include "Option.h"
using namespace std;
class Options {
unordered_map<string, Option> options;
int argc;
const char ** argv;
public:
Options(int argc, const char * argv[]);
~Options();
void parse();
void addOption(string optionName, string valueName, string description, OptionType type);
void addFlag(string flagName, string description);
void addOptionAlias(string aliasName, string optionName);
void getOption(string optionName);
void printHelp();
};
It's in options.cpp on the line Option option(valueName, description, type); that the error seems to stem from, but for the life of me, I can’t figure out why. As far as I can see, the constructor in Option takes the right types.
The problem is actually in the next line:
options[optionName]=option;
That first calls the operator[] in the map, that searchs for the given key and returns the associated value. If the key is not found, it insert a default initialized value connected to that key. Then this value is copy assigned with your option.
Do you see the problem? Your Option class does not have a default constructor, so it cannot be default initialized! Read carefully your error message, surely it is talking about the default constructor, not the one you are looking at.
You have several solutions. The easiest would be to write a default constructor for your class.
The alternative would be never to use operator[] in the map so that the default constructor is never needed. If that's what you want to do, to insert an item you write:
options.insert(std::make_pair(optionName, option));
Finally, if you are using C++11 (or later) and a compliant enough compiler, you can even build the object directly into the container: zero copy overhead and you don't even need the copy constructor!
options.emplace(std::piecewise_construct,
std::forward_as_tuple(optionName),
std::forward_as_tuple(valueName, description, type));
There's a mismatch between the declaration of the constructor in the header and the definition in the source file.
In header...
Option(string& valueName, string& description, OptionType& type);
In source file...
Option::Option(string valueName, string description, OptionType type){
Notice the parameters are defined as references (e.g., string&) in the header, but as objects (e.g., string) in the source.

initiating lists in the constructor's initialization list

I just moved from C to C++, and now work with lists.
I have a class called "message", and I need to have a class called "line",
which should have a list of messages in its properties. as I learned, the object's properties should be initialized in the constructor's initialization list, and i had the "urge" to initialize the messages list in addition to the rest of the properties (some strings and doubles). is that "urge" justified? does the list need to be initialized?
here is my code.
the purpose is to create an empty list of lines, and the constructor I'm talking about is the one in line.cpp
//-------------------
//Code for line.h:
//-------------------
#ifndef LINE_H_
#define LINE_H_
#include "message.h"
#include <string>
#include <list>
using namespace std;
namespace test
{
using std::string;
class Line
{
public:
// constractor with parameters
Line(const string& phoneStr, double callRate, double messageRate);
//function to get phone string
string getPhoneStr() const;
double getCallRate() const;
double getMessageRate() const;
double getLastBill() const;
void addMessage(const string& phoneStr);
private:
string mPhoneStr;
list<Message> mMessages;
double mMessageRate;
double mLastBill;
};
}
#endif /* LINE_H_ */
//-------------------
//Code for line.cpp:
//-------------------
#include "line.h"
namespace test
{
Line::Line(const string& phoneStr, double callRate, double messageRate)
: mPhoneStr(phoneStr), mCallRate(callRate), mMessageRate(messageRate),
mLastBill(0) {}
//getters:
string Line::getPhoneStr() const
{
return mPhoneStr;
}
double Line::getCallRate() const
{
return mCallRate;
}
double Line::getMessageRate() const
{
return mMessageRate;
}
double Line::getLastBill() const
{
return mLastBill;
}
}
//-------------------
//Code for message.h:
//-------------------
#ifndef MESSAGE_H_
#define MESSAGE_H_
#include <string>
namespace test
{
using std::string;
class Message
{
public:
// constractor with parameters
Message(const string& phoneStr);
//function to get phone string
string getPhoneStr() const;
//function to set new phone string
void setPhoneStr(const string& phoneStr);
private:
string mPhoneStr;
};
}
#endif /* MESSAGE_H_ */
//-----------------------------------------------------------------------
//---------------------
//code for message.cpp:
//---------------------
#include "message.h"
namespace test
{
Message::Message(const string& phoneStr) : mPhoneStr(phoneStr) {}
string Message::getPhoneStr() const
{
return mPhoneStr;
}
void Message::setPhoneStr(const string& phoneStr)
{
mPhoneStr = phoneStr;
}
}
The initialization list is for initializing any base classes and member variables. The body of the constructor is meant to run any other code that you need before the object can be considered initialized.
I'm having a hard time understanding your situation, but hopefully the above helps.
You don't have to do everything in the initialisation list. It's hard to tell without seeing some code, but it sounds like adding the messages would be better done in the body of the constructor.