This question already has answers here:
using vs. typedef - is there a subtle, lesser known difference?
(2 answers)
Closed 1 year ago.
I'm having a problem with my code, even my professor has no idea why this is the case.
He wants me to define the structure with using Persontype= struct{}; and not a normal definition of a structure. I don't understand why or what is the difference.
he also don't want us to include the .cpp file in main.
Normal definition of a struct works fine but not with this.
the error
In file included from ...\LABOR1TEST\main.cpp:3:
...\LABOR1TEST\test.hpp:12:6: warning: 'void test(const std::vector<<unnamed struct> >&)' used but never defined
void test(std::vector<PersonType> const &_Personen);
^~~~
[100%] Linking CXX executable LABOR1TEST.exe
CMakeFiles\LABOR1TEST.dir/objects.a(main.cpp.obj): In function `main':
.../LABOR1TEST/main.cpp:12: undefined reference to `test(std::vector<._56, std::allocator<._56> > const&)'
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe[3]: *** [CMakeFiles\LABOR1TEST.dir\build.make:120: LABOR1TEST.exe] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:95: CMakeFiles/LABOR1TEST.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:102: CMakeFiles/LABOR1TEST.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:137: LABOR1TEST] Error 2
here is my code
main.cpp
#include <iostream>
#include <vector>
#include "test.hpp"
int main() {
PersonType p;
p.Name = "Max";
std::vector<PersonType> TEMPVEC;
TEMPVEC.push_back(p);
TEMPVEC.push_back(p);
test (TEMPVEC);
return 0;
}
test.cpp
#include <iostream>
#include <vector>
#include <string>
#include "test.hpp"
void test(std::vector<PersonType> const &_Personen)
{
for (auto const &i : _Personen)
{
std::cout << i.Name << std::endl;
}
}
and my test.hpp
#include <vector>
#include <string>
#ifndef LABOR1TEST_TEST_HPP
#define LABOR1TEST_TEST_HPP
using PersonType = struct {
std::string Name;
};
void test(std::vector<PersonType> const &_Personen);
#endif //LABOR1TEST_TEST_HPP
CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(LABOR1TEST)
set(CMAKE_C++_STANDARD 11)
add_executable(LABOR1TEST main.cpp test.cpp test.hpp)
My interpretation
using PersonType = struct { ..... }; on a top-level will generate a different anonymous type in each translation unit (.cpp file, for simplicity) and then give it a name of PersonType in each translation unit. It does not matter that this statement happens inside test.hpp, all #includes are handled by preprocessor and do not matter when dealing with types.
So, PersonType in two translation units (main.cpp and test.cpp) actually refer to different types. In effect, main.cpp expects to find test(vector<PersonType> const &) with one PersonType, and test.cpp only provides test(vector<PersonType> const&) with another PersonType, hence the linkage error.
Is it a GCC bug?
You can see the error better if you get rid of templates and try compiling the following two translation units together:
using Foo = struct {};
void test(Foo);
int main() {
Foo f;
test(f);
}
using Foo = struct {};
void test(Foo) {
}
My GCC tells me the following:
a.cpp:2:6: error: 'void test(Foo)', declared using unnamed type, is used but never defined [-fpermissive]
2 | void test(Foo);
| ^~~~
a.cpp:1:7: note: 'using Foo = struct<unnamed>' does not refer to the unqualified type, so it is not used for linkage
1 | using Foo = struct {};
| ^~~
a.cpp:2:6: warning: 'void test(Foo)' used but never defined
2 | void test(Foo);
| ^~~~
However, replacing using Foo = struct {}; with typedef struct {} Foo; apparently works, as well as switching from my GCC to my Clang.
M.M from comments suggested that typedef should work because of [basic.link]/4.3
a named class ([class.pre]), or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage purposes ([dcl.typedef]);
It may get interpreted by GCC too literally(?) to exclude using, although [dcl.typedef]/2 says that the name introduced by using should have the same semantics as typedef.
Surprisingly, it was even asked on StackOverflow before!
Regarding your problem
He wants me to define the structure with using Persontype= struct{}; and not a normal definition of a structure.
If the text above is true, that's quite a strange requirement. It makes it impossible to link different translation units against PersonType. I'm wondering what's the rationale behind, maybe you're not supposed to actually expose PersonType beyond a single translation unit? Consider consulting with your TA or a professor.
Related
This question already has answers here:
Separating class code into a header and cpp file
(8 answers)
Closed 5 months ago.
I don't know how to add functions of a class outside its scope to it, use them in another class and then compile it.
MyMain.cpp
#include"MyClass.cpp"
int main(){
MyClass myClass;
myClass.run();
}
MyClass.cpp
#ifndef MYCLASS_CPP
#define MYCLASS_CPP
#include<iostream>
class MyClass {
private:
void usage();
public:
void run();
};
void MyClass::usage(){
std::cout << "usage called" << std::endl;
}
void MyClass::run(){
usage();
}
#endif
I try to compile it with:
g++ MyMain.cpp MyClass.cpp -o main
With that I get the following error message:
/usr/bin/ld: /tmp/ccN7GfOD.o: in function `MyClass::usage()':
MyClass.cpp:(.text+0x0): multiple definition of `MyClass::usage()'; /tmp/ccLhxS6v.o:MyMain.cpp:(.text+0x0): first defined here
/usr/bin/ld: /tmp/ccN7GfOD.o: in function `MyClass::run()':
MyClass.cpp:(.text+0x38): multiple definition of `MyClass::run()'; /tmp/ccLhxS6v.o:MyMain.cpp:(.text+0x38): first defined here
collect2: error: ld returned 1 exit status
If I have understood the concept correctly, the function headers within the class serve only as placeholders. The actual functionality is then "overwritten" by the external functions, which also contain a body.
And why does the error message say, that the function is already defined in the MyMain.cpp?
I have also seen that there are many similar questions here, but unfortunately I could not expand my understanding of the basic problem to solve it.
Is it possible that I am using the command to build the class with C++ incorrectly or that I can save the #include "MyClass.cpp"?
Kind regards
Several things wrong. here's the steps to put it right
Rename MyClass.cpp to MyClass.h.
Create a new empty file MyClass.cpp
Move the function definitions MyClass::usage() { .. } and MyClass::run() { .. } from MyClass.h to MyClass.cpp. You should probably also move #include <iostream> but this is not essential.
Add #include "MyClass.h" to MyClass.cpp
Change #include "MyClass.cpp" to #include "MyClass.h" in MyMain.cpp
Then build as you are doing now. That part is correct.
Essentially the technique is to separate your code into declarations and definitions. The declarations go into header files, which are included in the cpp files. The cpp files contain the definitions and are what you compile.
This question already has answers here:
Separating class code into a header and cpp file
(8 answers)
Closed 1 year ago.
Just had a little problem that I haven't been able to figure out yet.
I was using a similar program structure for a different project, but the problem boils down to this. I have two cpp files, which are:
Trading_dte.cpp :
#include <iostream>
using namespace std;
class Dte
{
public:
int addition(int a, int b)
{
return a + b;
}
};
dummy.cpp :
#include <iostream>
#include "Trading_dte.hpp"
Dte obj;
int check()
{
std::cout<<obj.addition(6,9);
}
I created a header file called Trading_dte.hpp :
# pragma once
#include <iostream>
class Dte
{
public:
int addition(int a, int b);
};
Now when I try compiling using the command :
g++ Trading_dte.cpp dummy.cpp
I get the error :
/usr/bin/ld: /tmp/ccCcM8R6.o: in function `check':
dummy.cpp:(.text+0x1a): undefined reference to `Dte::addition(int, int)'
collect2: error: ld returned 1 exit status
I'm sure it's something small, but I just can't figure what.
Thanks a lot in advance!
your cpp file need to be written differently
#include "Trading_dte.hpp"
#include <iostream>
int Dte::addition(int a, int b)
{
return a + b;
}
You've created two separate Dte classes, one visible to main and another visible only in Trading_dte.cpp. The one visible to main, defined in Trading_dte.hpp has a declaration of the addition member function but no definition.
Probably the easiest thing to do is to drop Trading_dte.cpp and put the implementation into the class definition in Trading_dte.hpp.
Trading_dte.hpp:
# pragma once
class Dte
{
public:
int addition(int a, int b)
{
return a + b;
}
};
Note that I also removed the #include <iostream> line. You don't need it in the header file because you don't use it in the class.
This question already has answers here:
Undefined reference to static class member
(9 answers)
Closed 8 years ago.
While linking this code:
#include <map>
using std::map;
#include <string>
using std::string;
class C {
public:
static void dump() {
for (const auto& e : data) {
string(e.first);
}
}
private:
static map<string,map<string,string>> data;
};
int main() {
C::dump();
}
... I get this error:
/tmp/cc4W2iNa.o: In function `C::dump()':
test.cpp:(.text._ZN1C4dumpEv[_ZN1C4dumpEv]+0x9): undefined reference to `C::data'
collect2: error: ld returned 1 exit status
... from g++ (GCC) 4.9.1.
Am I doing anything wrong?
You've declared C::data, but not defined it. Add a definition outside the class:
map<string,map<string,string>> C::data;
In a larger program, which more than one source file, this must go in just one source file to satisfy the One Definition Rule; while the class definition (including the declaration of data) might go in a header to be available wherever it's needed.
It seems that the IF_ID_WRITE class object that is declared in main and defined in a header file is not recognized by a function prototype in the same header file. When I move the prototype from Pipeline.h to Project.cpp, it compiles fine, but I don't want to resort to doing that.
What do I need to change to make it recognize the object type from Pipeline.h?
When I compile, I get the following three errors:
error C2065: 'IF_ID_WRITE' : undeclared identifier
error C2065: 'aIF_ID_WRITE' : undeclared identifier
error C2182: 'IF_stage' : illegal use of type 'void'
Pipeline.h file contains
#include <cstdlib>
#include <iomanip>
#include <iostream>
using namespace std;
#pragma once
//function prototypes
void IF_stage(IF_ID_WRITE &aIF_ID_WRITE);
//IF_ID_WRITE defined
class IF_ID_WRITE {
private:
int inst;
int writeRegNum;
int readReg1Num;
int readReg2Num;
int offset;
int incrPC;
public:
IF_ID_WRITE();
void setWriteRegNum(int);
void setReadReg1Num(int);
void setReadReg2Num(int);
~IF_ID_WRITE()
};
Project.cpp contains
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include "Pipeline.h"
using namespace std;
#pragma once
int main(){
.
.
.
IF_ID_WRITE aIF_ID_WRITE; //creating an object called aIF_ID_WRITE of type IF_ID_WRITE
IF_stage(aIF_ID_WRITE); //a function that will pass the object by reference
In the Pipeline.cpp file:
void IF_stage(IF_ID_WRITE& aIF_ID_WRITE)
{
//code
}
edited to show IF_ID_WRITE being defined in Pipeline.cpp
C++ is a top-down language, the type needs to be declared before you can declare a function that uses it. The compiler won't look-ahead to try to figure out whether IF_ID_WRITE exists later in the translation unit, it will just fail as it does not exist before the function declaration.
If you reorder the definition of the IF_ID_WRITE type and the function it should work. Since you are only declaring the function in the header, you can also provide a declaration of the type (no definition required) before the function declaration:
class IF_ID_WRITE;
void IF_stage(IF_ID_WRITE& aIF_ID_WRITE);
[There are other syntax issues, like the destructor missing (), but I assume this is an issue with the copy-paste into the question. I don't really believe this, but I'll skip the full code review]
Could someone please advise?
If const in C++ defaults to internal linkage, why do I get multiple definition errors in the code below?
First, the file dem.h:
#ifndef _DEM_H_
#define _DEM_H_
class Dem {
public:
static const int i;
};
const int Dem::i = 10;
#endif
Them imp1.cpp:
#include "dem.h"
#include <iostream>
using namespace std;
extern int foo();
int main() {
cout << foo() << endl;
}
and imp2.cpp:
#include "dem.h"
int foo() {
return Dem::i ;
}
I compile with the following command and results:
$ g++ imp1.cpp imp2.cpp
/tmp/ccmGt0OY.o:imp2.cpp:(.rdata+0x0): multiple definition of `Dem::i'
/tmp/cc5sN7dz.o:imp1.cpp:(.rdata+0x0): first defined here
collect2: ld returned 1 exit status
From C++11 [basic.link], paragraph 5:
In addition, a member function, static data member, a named class or enumeration of class scope, or an unnamed class or enumeration defined in a class-scope typedef declaration such that the class or enumeration has the typedef name for linkage purposes (7.1.3), has external linkage if the name of the class has external linkage.
Because your class has external linkage, so does your static data member.
Its static to the compilation unit. You are compiling in two steps - first impl1.cpp and then impl2.cpp - and in each unit the compiler instantiates the static data member. When the linker then tries to link the two associated object files together, it sees two different definitions for the same symbol , and so you get a multiple definition error.