function in main program OK, undefined references otherwise - c++

I have a function, that when defined in the main file of my program, works as I wish, and produces a lot of undefined references, when defined in a header file.
This header file exists:
#include "Domain.h"
#include "Character.h"
class Item {
public:
Character input;
Item(Character c2);
};
Item pistol(int which, float strength);
The function that makes problems is pistol. It looks like
Item pistol(int which, float strength) {
Interval i = Interval(0, 1);
Domain d = Domain(i);
Character c = Character({d}, {1});
return Item(c);
}
When I try to link the code with my main program, all calls that refer to object in Domain.h and Character.h are undefined references, that means I get linking time errors like:
undefined reference to `Character::show()'
...
undefined reference to `Interval::Interval(float, float)'
...
these errors are at places in the code, which are not inside the pistol function.
When I move this function to my main program, everything works as expected:
#include "Domain.h"
#include "Character.h"
#include "Item.h"
Item pistol(int which, float strength) {
// definition, see above
}
int main() {
Item w2 = pistol(2, 0.5);
return 0;
}
What is the problem with that function being in Item.h/Item.cxx?
What do I need to do to put it their?

undefined reference is a linking stage error.
You most probably missed to link with a compilation unit, missed to recompile a dependent compilation unit, or tried to have a template class/function definition not seen by the compiler from all your compilation units using it!

Related

Why do I get link errors when trying to create an instance of std::numpunct<char16_t> derivative?

I'm trying to make use of std::basic_stringstream<char16_t> with a UTF16-based std::numpunct. But an attempt to create even the simplest possible derivative of std::numpunct<char16_t> fails at link stage. Here's the code:
#include <locale>
struct my_punct : public std::numpunct<char16_t> {};
int main()
{
my_punct n;
}
And here are link errors (using g++ 7.2.0) (live test):
$ g++-7 test0.cpp -o test
/tmp/cc0oWPhL.o: In function `std::numpunct<char16_t>::numpunct(unsigned int)':
test0.cpp:(.text._ZNSt8numpunctIDsEC2Ej[_ZNSt8numpunctIDsEC5Ej]+0x36): undefined reference to `std::numpunct<char16_t>::_M_initialize_numpunct(__locale_struct*)'
/tmp/cc0oWPhL.o: In function `my_punct::~my_punct()':
test0.cpp:(.text._ZN8my_punctD2Ev[_ZN8my_punctD5Ev]+0x18): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0x8): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0xc): undefined reference to `std::numpunct<char16_t>::~numpunct()'
collect2: error: ld returned 1 exit status
If I change char16_t to char, linking completes successfully. So, what am I doing wrong here? Do I need some additional library to link against?
As a sanity check, I've tried grepping GCC installation for _ZTVSt8numpunctIDsE, and it gave no result. But grepping for _ZTVSt8numpunctIcE did find libstdc++.so.6.0.24. Does this mean I've found a bug in libstdc++?
It's because there isn't a supporting implementation for the specialized class. What happens when you utilize a template is that the compiler generates a symbol for that particular use. If there is already a predefined and fully templated implementation, then the compiler can make its own definition, but only if it sees the templated implementation when it compiles the file trying to use it. If it can't see it, then it just creates the symbol, leaves it undefined, and expects to link it later.
As a quick example...
in Template_Add.h
// Generic template
template< class T >
T add(T first, T second);
in Template_Add.cpp
// Specialized for int
template<>
int add<int>(int first, int second){
in main.cpp
#include "Template_Add.h"
int main(){
int ia, ib, ic;
double da, db, dc;
ia = 3;
ib = 4;
da = 3.0;
db = 4.0;
// we expect ia = 7, and works
ic = add(ib, ic);
// we expect dc = 7.0, but doesn't work
// this will result in an unresolved symbol
dc = add(da, db);
return 0;
}
The reason for this behavior is that there isn't a templated implementation that exists anywhere where main.cpp can see it. When everything is linked, however, the linker sees that an "int add(int, int)" exists, and so that is allowed.
If you own the template, then you can add the (templated) implementation into the .h file containing the template declaration. That way the compiler knows how to generate the symbol and definition at compile time. To fix our above example, we could add the following code to Template_Add.h:
template< class T >
T add(T first, T second){
return first + second;
}
...and then anything including "Template_Add.h" would be able to generate its own implementation for anything trying to make use of the template.
If you don't own the template, then the best you can do is find a way to use the supported template specializations. In this case, it might be best to cast (or typedef) your char16_t into a short, and then see if that works.

Forward declaration is not working as expected

I'm defining a class SpatialCriterionCallback in a header file "spatialcriterion.h" like this:
#include "ros/ros.h"
#include "neuromorphic_stereo/MatchingCandidates.h"
#include <vector>
class SpatialCriterionCallback
{
public:
// constructors & destructors
SpatialCriterionCallback()=default;
SpatialCriterionCallback(ros::NodeHandle);
~SpatialCriterionCallback()=default;
private:
std::vector<neuromorphic_stereo::MatchingCandidates> matching_candidates;
void subscriberCallbackFunction(constneuromorphic_stereo::MatchingCandidates&);
}
Then in the file "spatialcriterion.cpp" I'm defining a constructor that invokes a ros::SubscriberNode like this:
#include "spatialcriterioncallback.h"
SpatialCriterionCallback::SpatialCriterionCallback(ros::NodeHandle n)
{
this->n =n;
this->time_criterion_topic_handle = this->n.subscribe("TimeCriterionTopic",
1e4,
&SpatialCriterionCallback::subscriberCallbackFunction,
this);
}
When I try compiling this within a qtcreator project, the compiler tells me
error: undefined reference to
`SpatialCriterionCallback::subscriberCallbackFunction(neuromorphic_stereo::MatchingCandidates_ const&)'
When I add the following lines to my "spatialcriterion.cpp" file it will compile just fine:
void SpatialCriterionCallback::subscriberCallbackFunction(const neuromorphic_stereo::MatchingCandidates & msg){
this->matching_candidates.push_back(msg);
}
Now my question is: Shouldn't this code compile without the function definition, because the function subscriberCallbackFunction() has already been declared in "spatialcriterion.h"? Why is it necessary for the compiler to have the function defined?
I also tried finding an explanation to this behaviour here, but all the other posts about failing forward declaration (like this or this) aren't exactly what I'm looking for.
Even if you declared the method in your class, it doesn't exist.
When you reference that function in the constructor, the linker tells you that it needs to know where the method is.
The code compiles fine, it doesn't link.

Using static const string[] as a member instead of a global, initialized in the .cpp file

Related to this. I'd like to avoid using global variables so I resorted to using structs with enum and std::string[] (see link) in order to build menus for a small application. I would also like to have these enums in a separate header file. The selected answer in the link implies using --std=c++17, which I'd like to avoid, at least for now, and decided to use a static const std::string[] -- no need to include extra array or vector since this is initialized once, never modified, only called, ALL is always known.
As other answers on this have made it clear, I need to either initialize A::names outside the struct, or use a static const std::string& setter (see this, for example). But all the answers so far dealt with a std::string, not an array, std::string[].
This is a simple example of what I tried. It simply tries to print the contents of A::names using a for() loop iterating through the enum in struct A:
a.h:
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
#include <string>
struct A
{
enum E { ONE, TWO, ALL };
static const std::string names[ALL];
};
#endif // A_H_INCLUDED
a.cpp:
#include "a.h"
static const std::string A::names[A::ALL] { "one", "two" };
main.cpp:
#include "a.h"
#include <iostream>
int main()
{
for(int i=A::ONE; i<A::ALL; ++i)
std::cout << A::names[i] << '\n';
return 0;
}
The error after g++ main.cpp is:
main.cpp:(.text+0x24): undefined reference to `A::names[abi:cxx11]'
collect2: error: ld returned 1 exit status
Seeing the cxx11, I thought g++ --std=c++11 main.cpp would solve it, but it doesn't.
So, what am I doing wrong, or, how could I adapt the version with the setter to return an array, std::string[]? My goal is to have an alternative to a global variable, that has only one instance in memory no matter how many calls.
Here's an adapted code, from a small program, on how I would build a menu using struct with enum and string (menu_design = new QMenu... and menuDesignAction() is the function that updates):
for(unsigned char i=0; i<A::ALL; ++i) // needs initializing
{
QAction *tmpAction {new QAction(tr(A::names[i].c_str()))};
tmpAction->setObjectName(QString("%1").arg(i));
connect(tmpAction, SIGNAL(triggered(bool)), this, SLOT(menuDesignAction()));
menu_design->addAction(tmpAction);
}
As a side-note, in the snippet above, I have to use .c_str(), but I am using a std::string in the enum. If I could make it *char[] instead of std::string[], would I avoid extra calls? If I am not wrong, how could the answers to my problem (assuming there are) be adapted so as to be able to fit somehow in the Qt snippet?

c++ calling a class within a class

So i had the following code which ran perfectly.
Here "rngSource" makes an instance of the class contained in rand.h. rng.rFloat64() calls random numbers between 0 and 1.
main.cpp
#include "rand.h" // rngSource
rngSource rng;
class particle{
public:
double r[nd], v[nd];
particle()
{
for (int i=0; i<nd; ++i)
{
r[i]=L*rng.rFloat64();
v[i]=rng.rFloat64();
}
}
};
But when I tried to separate the class implementation from main.cpp into particle.h and particle.cpp, as indicated below:
particle.h
#ifndef particle_H
#define particle_H
class particle{
public:
double r[2], v[2];
particle();
};
#endif
particle.cpp
#include "rand.h" // rngSource
#include "particle.h"
particle::particle()
{
double ran = (double) rand()/(double)RAND_MAX;
static const double L=10;
for (int i=0; i<2; ++i)
{
r[i]=L*ran;
v[i]=ran;
}
}
While the new main.cpp looks like this:
#include "rand.h" /* rngSource() */
#include "particle.h" /* particle class */
rngSource rng;
int main(){
rng.rseed(getpid()*time(NULL));
particle p[N];
....
}
But when i try to compile i get the following errors:
particle.cpp: In constructor ‘particle::particle()’:
particle.cpp:20:17: error: ‘rng’ was not declared in this scope
r[i]=L*rng.rFloat64(); //ran;
^
particle.o:(.data+0x0): multiple definition of `rng_cooked'
new.o:(.data+0x0): first defined here
particle.o:(.data+0x1300): multiple definition of `kn'
new.o:(.data+0x1300): first defined here
particle.o:(.data+0x1500): multiple definition of `wn'
new.o:(.data+0x1500): first defined here
particle.o:(.data+0x1700): multiple definition of `fn'
new.o:(.data+0x1700): first defined here
new.cpp:(.text+0x1fb1): undefined reference to `rngSource::rseed(long long)'
particle.o: In function `particle::particle()':
particle.cpp:(.text+0x1fa2): undefined reference to `rngSource::rseed(long long)'
particle.cpp:(.text+0x1fb5): undefined reference to `rngSource::rFloat64()'
particle.cpp:(.text+0x1fda): undefined reference to `rngSource::rFloat64()'
collect2: error: ld returned 1 exit status
Would anyone here happen to know how to fix this?
thank you.
Three problems.
Problem 1:
particle.cpp: In constructor ‘particle::particle()’:
particle.cpp:20:17: error: ‘rng’ was not declared in this scope
r[i]=L*rng.rFloat64(); //ran;
The ultra cheesy answer is to add extern rngSource rng; to particle.cpp above the particle constructor. extern means this variable exists, but its storage is allocated elsewhere. The linker will track it down for you. This is quick, dirty, and will get you back on the road with minimal code changes.
Better solutions are to add extern rngSource rng; to rand.h and then define rngSource rng; in rand.cpp for all users or placing extern rngSource rng; in a brand new main.h and include main.h in particle and other modules called by main.
The best solution is probably to create a bool init(rngSource & rng) function in particle and do grunt work the constructor's currently doing. That way if rng doesn't exist, the compiler catches it when you try to call init.
particle p[N];
for (size_t index; index < N; index++)
{
p[index].init(rng);
}
Problem 2
particle.o:(.data+0x0): multiple definition of `rng_cooked'
new.o:(.data+0x0): first defined here
particle.o:(.data+0x1300): multiple definition of `kn'
new.o:(.data+0x1300): first defined here
particle.o:(.data+0x1500): multiple definition of `wn'
new.o:(.data+0x1500): first defined here
particle.o:(.data+0x1700): multiple definition of `fn'
new.o:(.data+0x1700): first defined here
rng_cooked, kn, wn, and fn are almost certainly being defined in rand.h. This means everyone who includes rand.h tries to create their own version of those variables resulting in collisions when the linker tries to line up names with storage locations.
Solution is similar to the first problem: Add extern to the variable definitions in the rand.h and define them in rand.cpp.
Problem 3
new.cpp:(.text+0x1fb1): undefined reference to `rngSource::rseed(long long)'
particle.o: In function `particle::particle()':
particle.cpp:(.text+0x1fa2): undefined reference to `rngSource::rseed(long long)'
particle.cpp:(.text+0x1fb5): undefined reference to `rngSource::rFloat64()'
particle.cpp:(.text+0x1fda): undefined reference to `rngSource::rFloat64()'
No idea. Are you certain you are passing rand.cpp to gcc?

C++ compiler issue (?): can't pass arguments to functions in separate class files [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is an undefined reference/unresolved external symbol error and how do I fix it?
I recently started working on an interpreter in C++, but I got annoyed that vectors or arrays could not be passed to external class methods no matter what I tried and so I deleted everything I had worked on. As it turns out, I can't pass even an int to another class. I decided to give C++ another chance before resorting to C or Java, but the compiler still doesn't work as I would expect. Maybe I'm forgetting something simple about C++, as I haven't used it in a while, but this seems simple enough. My problem is: I can't pass arguments to methods in other classes when they're not defined in the same file. Here's what I'm trying to do:
Main: main.cpp
#include "myclass.h"
int main() {
MyClass test;
int n = test.add(25, 30);
return n;
}
Header: myclass.h
class MyClass {
public:
int add(int a, int b);
};
Class implementation: myclass.cpp
#include "myclass.h"
int MyClass::add(int a, int b) {
return a + b;
}
Compiling this with g++ main.cpp yields
/tmp/ccAZr6EY.o: In function main':
main.cpp:(.text+0x1a): undefined reference toMyClass::add(int, int)'
collect2: error: ld returned 1 exit status
What the heck am I doing wrong? Also, the compiler yells at me for the same thing even if my functions aren't parameterized, so it must be a problem with the header.
Any help is much appreciated - thanks!
You need to compile both files
g++ main.cpp myclass.cpp
If you only compile main.cpp, the compiler finds the declaration of MyClass::add in your header but the linker later fails to find an implementation of MyClass::add to jump to.