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)
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 #include
s 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.
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!
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.