In my c++ program, I am getting this error:
Undefined symbols for architecture x86_64:
"MathExpression::layerFunctions", referenced from:
MathExpression::initializeLayerFunctions() in MathExpression.cpp.o
MathExpression::layer(MathExpression&, MathExpression::Operation,
std::__1::vector<short, std::__1::allocator<short> >&) in
MathExpression.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see
invocation)
make[3]: *** [MathTestGenerator] Error 1
make[2]: *** [CMakeFiles/MathTestGenerator.dir/all] Error 2
make[1]: *** [CMakeFiles/MathTestGenerator.dir/rule] Error 2
make: *** [MathTestGenerator] Error 2
I have this declaration in my header file:
static std::vector<std::function<void(MathExpression &, std::vector<NumberType> &)>> layerFunctions;
In my .cpp file, I have:
std::vector<std::function<void(MathExpression &, std::vector<MathExpression::NumberType> &)>> layerFunctions(static_cast<MathExpression::OperationType> (MathExpression::Operation::EOE));
along with this function:
void MathExpression::initializeLayerFunctions() {
layerFunctions.resize(static_cast<OperationType>(Operation::EOE));
layerFunctions[static_cast<unsigned long>(Operation::addition)] = [] (MathExpression & exp, std::vector<NumberType> & otherArgs) -> void {
exp.string.insert(exp.string.end(), {' ', operationToChar(Operation::addition), ' ', static_cast<CharType>
(otherArgs[0])});
};
layerFunctions[static_cast<unsigned long>(Operation::subtraction)] = [] (MathExpression & exp, std::vector<NumberType> & otherArgs) -> void {
exp.string.insert(exp.string.end(), {' ', operationToChar(Operation::subtraction), ' ', static_cast<CharType>
(otherArgs[0])});
};
layerFunctions[static_cast<unsigned long>(Operation::EOE)] = [] (MathExpression & exp, std::vector<NumberType> & otherArgs) -> void {
// Throw or assert or something.
};
}
I'm unsure as to what I could be doing wrong. As far as I can tell my declarations match up, but I can't get rid of the error. Would anyone have insight on how to solve this? Future thanks.
For reference, here are my header and .cpp files, respectively (bear in mind this is my first C++ program so I'm sure conventions are missing):
#ifndef MATHTESTGENERATOR_MATHEXPRESSION_H
#define MATHTESTGENERATOR_MATHEXPRESSION_H
#include <vector>
#include <functional>
class MathExpression {
public:
using FieldType = unsigned char;
using OperationType = unsigned char;
using NumberType = short int;
using CharType = char;
enum class Field : FieldType {
integers,
EOE // rational, real, complex.
};
enum class Operation : OperationType {
addition,
subtraction,
EOE // multiplication, division, absolute value, radical
};
explicit MathExpression(std::vector<CharType>);
std::vector<CharType> string;
static void print(MathExpression &);
static void layer(MathExpression &, Operation,
std::vector<NumberType> &);
static void initialize();
private:
static char operationToChar(OperationType);
static char operationToChar(Operation);
static std::vector<std::function<void(MathExpression &,
std::vector<NumberType> &)>> layerFunctions;
static void initializeLayerFunctions();
};
#endif //MATHTESTGENERATOR_MATHEXPRESSION_H
and
#include "MathExpression.h"
#include <list>
#include <iostream>
std::vector<std::function<void(MathExpression &,
std::vector<MathExpression::NumberType> &)>>
layerFunctions(static_cast<MathExpression::OperationType>, (MathExpression::Operation::EOE));
void MathExpression::initialize() {
initializeLayerFunctions();
}
void MathExpression::initializeLayerFunctions() {
layerFunctions.resize(static_cast<OperationType>(Operation::EOE));
layerFunctions[static_cast<unsigned long>(Operation::addition)] = [] (MathExpression & exp, std::vector<NumberType> & otherArgs) -> void {
exp.string.insert(exp.string.end(), {' ', operationToChar(Operation::addition), ' ', static_cast<CharType>
(otherArgs[0])});
};
layerFunctions[static_cast<unsigned long>(Operation::subtraction)] = []
(MathExpression & exp, std::vector<NumberType> & otherArgs) -> void {
exp.string.insert(exp.string.end(), {' ', operationToChar(Operation::subtraction), ' ', static_cast<CharType>
(otherArgs[0])});
};
layerFunctions[static_cast<unsigned long>(Operation::EOE)] = [] (MathExpression & exp, std::vector<NumberType> & otherArgs) -> void {
// Throw or assert or something.
};
}
char MathExpression::operationToChar(OperationType ordinal) {
return operationToChar(static_cast<Operation>(ordinal));
}
char MathExpression::operationToChar(Operation op) {
switch(op) {
case Operation::addition : return '+';
case Operation::subtraction : return '-';
default : return '_';
}
}
MathExpression::MathExpression(std::vector<CharType> exp) {
this->string = std::vector<CharType>(exp);
}
void MathExpression::print(MathExpression &exp) {
for(int i = 0; i < exp.string.size(); i++) {
std::cout << exp.string[i];
}
}
void MathExpression::layer(MathExpression &exp,
MathExpression::Operation op, std::vector<NumberType> &otherArgs) {
layerFunctions[static_cast<OperationType>(op)](exp, otherArgs);
}
The issue lies within MathExpression.CPP.
You defined layerFunctions, but since it is not within the MathExpressions namespace, I.E. MathExpressions::layerFunctions, it's saying that inside your header there is a linker error.
By adding that namespace to your function declaration, your problem should cease to be a problem.
You can find information about linker errors all over the place if you give them a quick google.
Related
I am very new to C++ and I was trying out templating to understand how it works. I have a template function that accepts an argument of type T. The problem that I am facing is that T's type is determined at runtime depending on the value of T and the compiler throws an error because it determines the type without considering the if-else-if-else block.
#include <iostream>
using namespace std;
class MyClass {
public:
void setInt(int x) {}
void setString(string y) {} // copy string object
};
void f1() {
cout << "break" << endl;
}
template<typename T, typename... Args>
void f1(T arg, Args... args) {
string _type(typeid(arg).name());
cout << __PRETTY_FUNCTION__ << endl;
cout << _type << endl;
MyClass c1;
if( _type.compare("i") == 0 ) {
c1.setInt(arg);
} else if ( _type.compare("PKc") == 0 ) {
//c1.setString(arg);
}
f1(args...);
};
int main() {
f1(7, 3.3, "asd", 0xa1);
return 0;
}
The output:
prog.cpp: In instantiation of ‘void f1(T, Args ...) [with T = const char*; Args = {int}]’:
prog.cpp:30:4: recursively required from ‘void f1(T, Args ...) [with T = double; Args = {const char*, int}]’
prog.cpp:30:4: required from ‘void f1(T, Args ...) [with T = int; Args = {double, const char*, int}]’
prog.cpp:35:24: required from here
prog.cpp:25:13: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
c1.setInt(arg);
^~~
prog.cpp:6:19: note: initializing argument 1 of ‘void MyClass::setInt(int)’
void setInt(int x) {}
~~~~^
https://ideone.com/the4AP (The link to online compiler)
One possible approach:
void f1_helper(int arg, MyClass* c) {
c->setInt(arg);
}
void f1_helper(string arg, MyClass* c) {
c->setString(arg);
}
template<typename... Args>
void f1(Args... args) {
MyClass c1;
auto _ = {(f1_helper(args, &c1), 0) ...};
}
Demo
I have two omnetpp projects: Lab1 and Lab2
From Lab1 .so library is created. Lab 2 is supposed to use this library. It is clear how to import and use modules declared in .ned-files. Problems begin when I try to use message-type from the library (Bitmessage).
bitmessage.msg from the library:
message Bitmessage {
bool bit;
}
sSource.h in Lab2:
#ifndef SSOURCE_H_
#define SSOURCE_H_
#include <omnetpp.h>
#include "bitmessage_m.h"
class sSource : public cSimpleModule
{
protected:
virtual void initialize();
virtual void handleMessage(cMessage *msg);
private:
double p;
};
Define_Module(sSource);
#endif /* SSOURCE_H_ */
sSource.cc - source-file in Lab2 which is suppose to use bitmessage:
#include <sSource.h>
/*virtual*/ void sSource::initialize()
{
p = par("p").doubleValue();
}
/*virtual*/ void sSource::handleMessage(cMessage *msg)
{
if (msg->getArrivalGate() == gate("in"))
{
delete msg;
Bitmessage* bit_msg = new Bitmessage(); // **(!!!)here is error**
int num_outs = this->gateSize("out");
for (int i = 0; i < num_outs; ++i)
{
send(bit_msg->dup(), "out", i);
}
delete bit_msg;
}
else
{
delete msg;
}
}
The error is following:
undefined reference to `Bitmessage::Bitmessage(char const*, int)'
How to deal with it? Maybe the problem is that compiler can't interpret .msg-file from the library?
Believe me when I tell you that I searched online, but did not find the answer.
I have 5 files:
main.cpp
Game.cpp
Game.hpp
Window.cpp
Window.hpp
The content is below :
#include "Window.hpp"
#include "Game.hpp"
int main()
{
// Program entry point
Game game;
while (!game.GetWindow()->IsDone()){
// game loop here
game.HandleInput();
game.Update();
game.Render();
}
return 0;
}
This is the Game.cpp
#include "Window.hpp"
class Game {
public:
Game(): m_window("Chapter 2", sf::Vector2u(800,600)) {
m_mushroomTexture.loadFromFile("images.png");
m_mushroom.setTexture(m_mushroomTexture);
}
~Game(){}
void HandleInput() {
}
void Update() {
m_window.Update();
MoveMushroom();
}
void Render() {
m_window.BeginDraw();
m_window.Draw(m_mushroom);
m_window.EndDraw();
}
// Getting a point to the window
Window* GetWindow(){
}
private:
void MoveMushroom(){
sf::Vector2u l_windSize = m_window.GetWindowSize();
sf::Vector2u l_textSize = m_mushroomTexture.getSize();
if ((m_mushroom.getPosition().x > l_windSize.x - l_textSize.x and m_increment.x > 0) or \
(m_mushroom.getPosition().x < 0 and m_increment.x < 0)) {
m_increment.x = -m_increment.x;
}
if ((m_mushroom.getPosition().y > l_windSize.y - l_textSize.y and m_increment.y > 0) or \
(m_mushroom.getPosition().y < 0 and m_increment.y < 0)) {
m_increment.y = -m_increment.y;
}
m_mushroom.setPosition( m_mushroom.getPosition().x + m_increment.x, m_mushroom.getPosition().y + m_increment.y);
}
Window m_window;
sf::Texture m_mushroomTexture;
sf::Sprite m_mushroom;
sf::Vector2i m_increment;
};
Game.hpp
#pragma once
#include "Window.hpp"
#include <SFML/Graphics.hpp>
class Game {
public:
Game();
~Game();
void HandleInput();
void Update();
void Render();
// Getting a point to the window
Window* GetWindow();
private:
void MoveMushroom();
Window m_window;
sf::Texture m_mushroomTexture;
sf::Sprite m_mushroom;
sf::Vector2i m_increment;
};
Window.cpp
#include <SFML/Graphics.hpp>
#include <string>
class Window {
public:
// constructor
Window() {Setup("Window", sf::Vector2u(640,480));}
// we have 2 constructors because there 2 ways to instantiate a class
Window(const std::string& l_title, const sf::Vector2u& l_size) {
Setup(l_title, l_size);
}
~Window() { Destroy(); }
void BeginDraw(){
m_window.clear(sf::Color::Black);
}
void EndDraw(){
m_window.display();
}
void Update(){
sf::Event event;
while (m_window.pollEvent(event)) {
if (event.type == event.Closed) {
m_isDone = true;
} else if (event.type == sf::Event::KeyPressed and event.key.code == sf::Keyboard::F5){
ToggleFullscreen();
}
}
}
bool IsDone(){
return m_isDone;
}
bool IsFullscreen(){
return m_isFullscreen;
}
sf::Vector2u GetWindowSize() {
return m_windowSize;
}
void ToggleFullscreen(){
m_isFullscreen = !m_isFullscreen;
Destroy();
Create();
}
void Draw(sf::Drawable& l_drawable){
m_window.draw(l_drawable);
}
private:
void Setup(const std::string& l_title, const sf::Vector2u& l_size) {
m_windowTitle = l_title;
m_windowSize = l_size;
m_isFullscreen = false;
m_isDone = false;
Create();
}
void Destroy(){
m_window.close();
}
void Create() {
// the same as
// if (m_isFullscreen) {
// auto_style = sf::Style::Fullscreen;
// } else {
// auto_style = sf::Style::Default;
// }
auto style = (m_isFullscreen ? sf::Style::Fullscreen : sf::Style::Default);
m_window.create({m_windowSize.x, m_windowSize.y, 32}, m_windowTitle, style);
}
sf::RenderWindow m_window;
sf::Vector2u m_windowSize;
std::string m_windowTitle;
bool m_isDone;
bool m_isFullscreen;
};
Window.hpp
#pragma once
#include <SFML/Graphics.hpp>
#include <string>
class Window {
public:
// constructor
Window();
// we have 2 constructors because there 2 ways to instantiate a class
Window(const std::string& l_title, const sf::Vector2u& l_size);
~Window();
void BeginDraw();
void EndDraw();
void Update();
bool IsDone();
bool IsFullscreen();
sf::Vector2u GetWindowSize();
void ToggleFullscreen();
void Draw(sf::Drawable& l_drawable);
private:
void Setup(const std::string& l_title, const sf::Vector2u& l_size);
void Destroy();
void Create();
sf::RenderWindow m_window;
sf::Vector2u m_windowSize;
std::string m_windowTitle;
bool m_isDone;
bool m_isFullscreen;
};
The problem is that when i try to build my project i get a linker error.
/tmp/ccxbe5nA.o: In function `main':
main.cpp:(.text+0x26): undefined reference to `Game::Game()'
main.cpp:(.text+0x35): undefined reference to `Game::GetWindow()'
main.cpp:(.text+0x3d): undefined reference to `Window::IsDone()'
main.cpp:(.text+0x53): undefined reference to `Game::HandleInput()'
main.cpp:(.text+0x62): undefined reference to `Game::Update()'
main.cpp:(.text+0x71): undefined reference to `Game::Render()'
main.cpp:(.text+0x87): undefined reference to `Game::~Game()'
main.cpp:(.text+0xac): undefined reference to `Game::~Game()'
collect2: error: ld returned 1 exit status
I am compiling first with the following command :
g++ -std=c++11 -c main.cpp Window.cpp Game.cpp
No errors during the compilation stage. When I try to link it, I get the error message from above. The command used is this :
g++ main.o Game.o Window.o -o sfml-app -lsfml-graphics -lsfml-window -lsfml-system
By defining the same class differently in different places, your program violates One Definition Rule:
[basic.def.odr]/5 There can be more than one definition of a class type ... in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
— each definition of D shall consist of the same sequence of tokens; and...
Emphasis mine.
Remove class definition from Game.cpp, only leave member function definitions, like this:
Game::Game(): m_window("Chapter 2", sf::Vector2u(800,600)) {...}
void Game::Update() {...}
// and so on for other members
And similarly for Window.
You define each class twice, which is incorrect.
In your .cpp files it needs to provide definitions for functions declared but not defined in the headers.
E.g., Windows.cpp should include Windows.hpp and contain:
bool Windows::IsDone() {
return m_isDone;
}
In C++11, I implement function template specialization for identifying inheritance, but it occurred compile-time errors.
f() checks whether the specified class is derived from Base or not.
Following is a source code.
#include <iostream>
#include <type_traits>
using namespace std;
struct Base {};
struct Derived : Base {};
struct Base2 {};
template<typename T, bool = std::is_base_of<Base, T>::value>
void f() {
cout << "T is not Base or Base-derived class." << endl;
};
template<typename T>
void f<T, true>() {
cout << "T is Base or Base-derived class." << endl;
};
int main() {
f<Base>(); // ok
f<Derived>(); // ok
f<Base2>(); // not ok
return 0;
}
Following is error messages.
prog.cpp:15:17: error: non-class, non-variable partial specialization 'f<T, true>' is not allowed
void f<T, true>() {
^
prog.cpp: In function 'int main()':
prog.cpp:20:13: error: call of overloaded 'f()' is ambiguous
f<Base>();
^
prog.cpp:10:6: note: candidate: void f() [with T = Base; bool <anonymous> = true]
void f() {
^
prog.cpp:15:6: note: candidate: void f() [with T = Base]
void f<T, true>() {
^
prog.cpp:21:16: error: call of overloaded 'f()' is ambiguous
f<Derived>();
^
prog.cpp:10:6: note: candidate: void f() [with T = Derived; bool <anonymous> = true]
void f() {
^
prog.cpp:15:6: note: candidate: void f() [with T = Derived]
void f<T, true>() {
^
prog.cpp:22:14: error: call of overloaded 'f()' is ambiguous
f<Base2>();
^
prog.cpp:10:6: note: candidate: void f() [with T = Base2; bool <anonymous> = false]
void f() {
^
prog.cpp:15:6: note: candidate: void f() [with T = Base2]
void f<T, true>() {
^
How can I solve it?
When std::is_base_of<Base, T>::value evaluates true you have two functions with same signature. Therefore you get error "call ... is amibguous".
Try simple overloading as one of the solutions:
namespace detail {
void doIt(std::false_type) {
cout << "T is not Base or Base-derived class." << endl;
};
void doIt(std::true_type) {
cout << "T is Base or Base-derived class." << endl;
};
}
template<typename T>
void f() {
detail::doIt(typename std::is_base_of<Base, T>::type());
};
Of course the function detail::doIt() can be more complex and templated by T.
EDIT: add "detail::" into a function f() call.
The following sample code works fine under linux using g++4.8.2, using boost1_56. However, I get a strange linker error under MacOS X (Yosemite) using clang:
ld: internal error: atom not found in symbolIndex(__ZNSt3__112__hash_tableINS_17__hash_value_typeIKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEN15FRUIT_TUPLES4dataEEENS_22__unordered_map_hasherIS8_SB_NS9_8key_hashELb1EEENS_21__unordered_map_equalIS8_SB_NS9_9key_equalELb1EEENS5_ISB_EEE15__insert_uniqueIRKNS_4pairIS8_SA_EEEENSL_INS_15__hash_iteratorIPNS_11__hash_nodeISB_PvEEEEbEEOT_) for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Proces
The main.cpp file
#include "TupleFruits.hpp"
int main()
{
map_t fruitHash = InitializeFruitHash();
std::string fruit = "BANANA";
auto itr = fruitHash(fruit);
if (fruitHash.end() == itr)
{
std::cout << fruit << " not found in hash" << std::endl;
exit(1);
}
}
The FruitHash.cpp file:
#include "TupleFruits.hpp"
map_t InitializeFruitHash()
{
static map_t m;
data dBANANA = {0, 0, 6, false};
data dGRAPEFRUIT = {1, 1, 6, false};
data dSTRAWBERRY = {2, 2, 6, false};
m[BANANA] = dBANANA;
m[GRAPEFRUIT] = dGRAPEFRUIT;
m[STRAWBERRY] = dSTRAWBERRY;
return m;
}
The include file "HashData.hpp
#ifndef HASH_DATA_HPP
#define HASH_DATA_HPP
#include <string>
#include <unordered_map>
#include <cstring>
#include <iostream>
#include <tuple>
#include <boost/functional/hash.hpp>
typedef std::string fruit_key_t;
namespace HASH_TUPLES
{
struct key_hash : public std::unary_function<fruit_key_t, std::size_t>
{
std::size_t operator()(const fruit_key_t& k) const
{
std::hash<std::string> hash_fn;
return hash_fn(k);
}
};
struct key_equal : public std::binary_function<fruit_key_t, fruit_key_t, bool>
{
bool operator()(const fruit_key_t& v0, const fruit_key_t& v1) const
{
return (v0 == v1);
}
};
struct data
{
int row;
int column;
int precision;
bool isRipe;
inline bool operator ==(data d)
{
if (d.row == row && d.column == column)
return true;
else
return false;
}
friend std::ostream& operator << (std::ostream& os, const data& rhs) //Overloaded operator for '<<'
{ //for struct output
os << rhs.row << ", "
<< rhs.column;
return os;
}
};
typedef std::unordered_map<const fruit_key_t, data, key_hash, key_equal> map_t;
// ^ this is our custom hash
}
template<class T>
struct map_data_compare : public std::binary_function<typename T::value_type,
typename T::mapped_type,
bool>
{
public:
bool operator() (typename T::value_type &pair,
typename T::mapped_type i) const
{
return pair.second == i;
}
};
#endif
The include file "TupleFruits.hpp"
#ifndef TUPLESFRUITS_HPP
#define TUPLESFRUITS_HPP
#include <boost/interprocess/containers/string.hpp>
#include "HashData.hpp"
using namespace HASH_TUPLES;
map_t InitializeFruitHash();
static std::string BANANA = "banana";
static std::string GRAPEFRUIT = "grapefruit";
static std::string STRAWBERRY = "strawberry";
#endif
I figured it out. Somehow -s (strip all symbols from binary) snuck in my Makefile