I am trying to create a global function template specialized for some given types. It looks something like that:
A.h (primary template, template specialization, extern)
template <typename T> void foo() { std::cout << "default stuff" << std::endl; }
template<> void foo<int>() { std::cout << "int stuff" << std::endl; }
extern template void foo<int>();
A.cpp (explicit instantiation)
template void foo<int>();
B.h
void bar();
B.cpp (includes A.h)
void bar() { foo<int>(); }
main.cpp
foo<int>();
bar();
The compiler crashes on me: "multiple definitions of 'void foo()'. I thought that the extern was supposed to take care of this. The B compile unit should not instantiate foo, and instead use the A instantiation at link time, no? What am I getting wrong here?
Note that if I do not specialize foo, the code compiles just fine. Is there some kind of conflict between function specialization and instantiation?
You don't need extern here to suppress instantiation. By declaring an explicit specialization, you're already telling any code that calls foo<int> to use the explicit specialization rather than the primary template. Instead, you simply want to declare the specialization in A.h and then define it in A.cpp:
// A.h
template <typename T> void foo() { std::cout << "default stuff" << std::endl; }
template <> void foo<int>();
// A.cpp
template <> void foo<int>() { std::cout << "int stuff" << std::endl; }
Your use of extern would be appropriate if you wanted to provide an explicit instantiation of the primary template in some translation unit, and not an explicit specialization.
As Brian's answer gives you a working solution and explains why you don't need extern, I will elaborate a little bit more on your situation.
First, you stated that your compiler was crashing on you so you were assuming it was a compiler error. This is not the actual case. With your code as it was, A.cpp, B.cpp & main.cpp all compiled successfully on their own. There were no compilation errors. In visual studio 2017 CE, it wasn't until I tried to build the program until it crashed. Here is my IDE's build error.
1>------ Build started: Project: Temp, Configuration: Debug Win32 ------
1>B.obj : error LNK2005: "void __cdecl foo<int>(void)" (??$foo#H##YAXXZ) already defined in A.obj
1>main.obj : error LNK2005: "void __cdecl foo<int>(void)" (??$foo#H##YAXXZ) already defined in A.obj
1>C:\Users\...\Temp.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Done building project "Temp.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
What you have here is a Linking error. It is failing to link because of multiple defined symbols.
Let's go over your code:
A.h
#pragma once
#include <iostream>
// Not just a declaration of void foo<T>() but also a definition!
template<typename T> void foo() { std::cout << "default stuff\n"; }
// Not just a declaration of void foo<int>() but also a specialized definition!
template<> void foo<int>() { std::cout << "int stuff\n"; }
// external explicit instantiation
extern template void foo<int>();
A.cpp
#include "A.h"
// explicit instantiation
template void foo<int>();
B.h
#pragma once
void bar();
B.cpp
#include "B.h"
#include "A.h"
void bar() {
// instantiation to call foo
foo<int>();
}
main.cpp
#include "A.h"
#include "B.h"
int main() {
// instantiation to call foo
foo<int>();
bar();
return 0;
}
What is happening here is all 3 are compiling, but when it goes to the linker to build a single executable by passing the three object files it fails. The compiler just checks for language grammar - syntax and converts it to object files. The linker receives the object files from the compiler and creates all of the needed symbols for variables, functions, classes etc.
It looks in main and sees #include "A.h" and #include "B.h" So the pre compiler had already did the text substitution and pasted A.h and B.h at the top of the page, so all of the code that was in A.h & B.h that belongs to A.cpp and B.cpp translations units are also now in main.cpp translation unit. So it sees the foo template objects and it happens to see more than one definition! It has nothing to do with your use of extern. To demonstrate this, I can remove some of your code and still generate the same build error where it fails to link because of multiple definitions.
A.h
#pragma once
#include <iostream>
template<typename T> void foo() { std::cout << "default stuff\n"; }
template<> void foo<int>() { std::cout << "int stuff\n"; }
A.cpp
#include "A.h"
main.cpp
#include "A.h"
int main() {
foo<int>();
return 0
}
Give basically the same build-linking error:
1>------ Build started: Project: Temp, Configuration: Debug Win32 ------
1>main.cpp
1>main.obj : error LNK2005: "void __cdecl foo<int>(void)" (??$foo#H##YAXXZ) already defined in A.obj
1>C:\Users\...\Temp.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Done building project "Temp.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The only difference between the two is that the multiple definition is found in A & B where in the 2nd instance without even using B there is a multiple definition found A.
To resolve this use Brian's answer! Basically the rule of thumb is to have declarations in headers and definitions in cpp files unless if your definitions are in a specific class or namespace and not at the global scope.
Related
I have a struct containing two functions, one of which is a template function that calls the other. For the sake of organization, I'd like to separate these member functions into separate implementation files instead of defining them all in main.cpp. Visual Studio throws an unresolved external symbol error.
header.hpp:
#pragma once
struct Structure {
void function();
template<bool> void templateFunc();
Structure();
};
implementation.cpp:
#include "header.hpp"
void Structure::function() { return; }
main.cpp:
#include "header.hpp"
template<bool N> void Structure::templateFunc() { return function(); }
Structure::Structure() {}
int main() {
Structure object;
object.function(); // no error
object.templateFunc<0>(); // unresolved external symbol
}
LNK2019: unresolved external symbol 'public: void __cdecl Structure::function(void)' referenced in function 'public: void __cdecl Structure::templateFunc<0>(void)'
When I define the function in main, it compiles and runs.
main.cpp:
#include "header.hpp"
void Structure::function() { return; } // defined in main
template<bool N> void Structure::templateFunc() { return function(); }
Structure::Structure() {}
int main() {
Structure object;
object.function(); // no error
object.templateFunc<0>(); // no error
}
I was initially under the suspicion that my compiler was excluding implementation.cpp, but it fails to compile when syntax errors are present. Oddly, I don't receive a multiple declaration error when the function is defined in both files. I tried reprogramming this from scratch on another device and encountered the same error. I've ensured everything is explicitly included in compilation.
The code I'm hoping for is functionally identical to the code I've found works, but this example represents a larger project I'd like to organize.
Why is this happening? How can I define this function in a separate file?
I have Foo and Bar as follows:
Foo.h
#include <list>
using namespace std;
class Foo
{
private:
template <typename BarT>
list<BarT*> barT_lst;
public:
template <typename BarT>
Foo(void);
~Foo(void);
};
Foo.cpp
#include "Foo.h"
template <typename BarT>
Foo::Foo(void)
{
}
Foo::~Foo(void)
{
}
Bar.h
class Bar
{
public:
Bar(void);
~Bar(void);
};
Bar::Bar(void)
{
}
Bar::~Bar(void)
{
}
And main()
#include "Foo.h"
#include "Bar.h"
int _tmain(int argc, _TCHAR* argv[])
{
Foo<Bar> foo = Foo<Bar>();
return 0;
}
I use VC++2008. Every time when I build project, it shows errors:
1>------ Build started: Project: Test, Configuration: Debug Win32 ------
1>Compiling...
1>Test.cpp
1>c:\users\duong2179\documents\visual studio 2008\projects\test\test\foo.h(12) : fatal error C1001: An internal error has occurred in the compiler.
1>(compiler file 'msc1.cpp', line 1411)
1> To work around this problem, try simplifying or changing the program near the locations listed above.
1>Please choose the Technical Support command on the Visual C++
1> Help menu, or open the Technical Support help file for more information
1>Build log was saved at "file://c:\Users\duong2179\Documents\Visual Studio 2008\Projects\Test\Test\Debug\BuildLog.htm"
1>Test - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
This looks very strange. Please help!
Getting an access violation from the compiler should not really happen, it would be good to upgrade compiler.
However your code is also illegal. If you intend to write Foo<Bar> foo; then Foo needs to be a template, for example:
template<typename BarT>
class Foo
{
std::list<BarT *> barT_lst;
public:
Foo();
~Foo();
};
template<typename BarT>
Foo<BarT>::Foo()
{
// constructor code here
}
Note: this class probably violates Rule of Three , you should not have a container of raw pointers unless those pointers do not own what they are pointing to. (In which case you don't need a destructor).
Try to put the implementation of Foo class in same Foo.h file, i.e after class declaration.
I have files::
//ClassA.h
#ifndef ClassA_H
#define ClassA_H
#pragma once
class ClassA
{
public:
void func1(){
}
ClassA(void) {
}
~ClassA (void) {
}
};
#endif
//ClassA1.h
#include "ClassA.h"
class ClassA1 {
ClassA<2> b;
};
//ClassA1.cpp
#include "ClassA1.h"
//main_file.cpp
#include "ClassA1.h"
#include "iostream"
int main (int argc , char** argv) {
std::cout<<"in main"<<std::endl;
}
So this compiles fine...As soon as i define function of class ClassA outside the class in Class.h i get following error during build
1> LINK : c:\users\adudeja\documents\visual studio 2010\Projects\Test\Debug\Test.exe not found or not built by the last incremental link; performing full link
1>ClassA1.obj : error LNK2005: "public: void __thiscall ClassA::func1(void)" (?func1#ClassA##QAEXXZ) already defined in main_file.obj
1>ClassA1.obj : error LNK2005: "public: __thiscall ClassA::ClassA(void)" (??0ClassA##QAE#XZ) already defined in main_file.obj
1>ClassA1.obj : error LNK2005: "public: __thiscall ClassA::~ClassA(void)" (??1ClassA##QAE#XZ) already defined in main_file.obj
1>c:\users\adudeja\documents\visual studio 2010\Projects\Test\Debug\Test.exe : fatal error LNK1169: one or more multiply defined symbols found
So what is the difference between defining function outside class and inside class.
Below is the non working code...
#ifndef ClassA_H
#define ClassA_H
#pragma once
class ClassA
{
public:
void func1();
ClassA(void);
~ClassA(void);
};
void ClassA::func1(){
}
ClassA::ClassA(void) {
}
ClassA::~ClassA (void) {
}
#endif
So what is the difference between defining function outside class and inside class.
When you define it in the class body it is implicitly inline, and an inline function can be defined in multiple files.
A non-inline function must be defined exactly once only.
So either put the non-inline definition into a single .cpp file, not in a header included by multiple files, or define it with the inline keyword.
OK, let's see...
In your example, no function is defined outside the class declaration.
Both ClassA1.cpp and main_file.cpp "see" the definition of ClassA. Since all functions defined inside a class declaration are considered inline, i.e. the linker does not see it as a seperate function at all, and has nothing to complain about.
But if you put the definition of e.g. func1() outside the class declaration (but still in ClassA), it's no longer considered inline, it's a seperate function. But as it is still visible to two compilation units, it gets compiled in both translation units.
So when you attempt to link the two object files together, you got two instances of func1(), and the linker complains.
The solution is to either:
define a function inside the class declaration, or
define the function in one seperate translation unit (ClassA.cpp), and link with that.
Using templates limits your options somewhat, as template code must be visible to each translation unit it is used in, i.e. you cannot just declare it in a header and implement it elsewhere, leaving you with only option 1. above.
Post-code-review:
ClassA.hpp:
#ifndef ClassA_HPP
#define ClassA_HPP
class ClassA
{
public:
ClassA();
~ClassA();
void func1();
};
#endif
ClassA.cpp:
#include "ClassA.hpp"
void ClassA::func1()
{
// ...
}
ClassA::ClassA()
{
// ...
}
ClassA::~ClassA()
{
// ...
}
ClassA1.hpp:
#ifndef ClassA1_HPP
#define ClassA1_HPP
#include "ClassA.hpp"
// Your example still assumed that ClassA is a template,
// so I twisted that into an inheritance instead since
// ClassA isn't a template anymore, and if it *were* a
// template, it would change things significantly.
// Perhaps trying too much at once?
class ClassA1 : public ClassA
{
// ...
};
#endif
ClassA1.cpp:
#include "ClassA1.hpp"
// ...
main_file.cpp:
#include "ClassA1.hpp"
#include <iostream>
int main( int argc, char * argv[] )
{
std::cout << "in main" << std::endl;
return 0;
}
C Example
bb.c:
#include "bb.h"
#include <stdio.h>
void bb() {
printf("aa()...\n");
aa();
}
main.c:
#include "aa.h"
#include "bb.h"
int main(int argc, const char** argv) {
aa();
bb();
return 0;
}
aa.h:
#ifndef aa_h
#define aa_h
#include <stdio.h>
void aa() {
printf("aa()...\n");
}
#endif // aa_h
bb.h:
#ifndef bb_h
#define bb_h
#include "aa.h"
void bb();
#endif // bb_h
C Result
Compiled with clang main.c bb.c:
duplicate symbol _aa in:
/var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/main-OsFJVB.o
/var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/bb-OkcMzn.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
C++ Example
b.cpp:
#include "b.hpp"
void b::do_something_else() {
std::cout << "b::do_something_else() being called..." << std::endl;
a a;
a.doit();
}
main.cpp:
#include "a.hpp"
#include "b.hpp"
int main() {
a a;
b b;
a.doit();
b.do_something_else();
return 0;
}
a.hpp:
#ifndef a_hpp
#define a_hpp
#include <iostream>
class a{
public:
void doit() {
std::cout << "a::doit() being called..." << std::endl;
}
};
#endif // a_hpp
b.hpp:
#ifndef b_hpp
#define b_hpp
#include "a.hpp"
#include <iostream>
class b{
public:
void do_something_else();
};
#endif // b_hpp
C++ Result
The above compiles fine with clang++ main.cpp b.cpp and the output to the program is:
a::doit() being called...
b::do_something_else() being called...
a::doit() being called...
Questions
Why does the duplicate error not occur with the C++ version?
Does the fact that the function void a::doit() is defined in the header file rather than a source file mean that the compiler will automatically inline the function?
In C++ class methods are not top-level symbols, but are effectively scoped names within their class hierarchy.
This means that you have defined in C++ two doit() methods, a::doit() and b::doit()
In C, you have attempted to define one aa() function twice.
Note that C++ will give an error too if you define the doit() method twice, within the scope of the same class.
#include <iostream>
class a {
public:
void doit() {
std::cout << "hello" << std::endl;
}
void doit() {
std::cout << "goodbye" << std::endl;
}
};
leads to
ed.cpp:11:8: error: ‘void a::doit()’ cannot be overloaded
void doit() {
^
ed.cpp:7:8: error: with ‘void a::doit()’
void doit() {
^
In your C example, aa is defined twice, which violates the "one definition rule". This would be equally true if it were C++.
In your C++ example, a::doit is defined twice, but it is implicitly declared inline. Member functions defined within a class are implicitly inline per [dcl.fct.spec]/3:
A function defined within a class definition is an inline function. ...
inline functions are an exception to the one definition rule (in fact, this is the only meaning of inline required by the standard) per [basic.def.odr]/5.
There can be more than one definition of a ... inline function with external linkage (7.1.2) ... in a program, provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. ...
The requirements essentially boil down to a requirement that the definitions be identical in every translation unit where they appear.
Had you declared aa as inline, similar rules would have applied and your code would have compiled and worked as expected.
Why does the duplicate error not occur with the C++ version?
Because there is no duplication. C++ member functions are scoped by the class they are defined in. b::doit() isn't a duplicate of a::doit().
Does the fact that the function void a::doit() is defined in the header file rather than a source file mean that the compiler will automatically inline the function?
No, but it means it is possible.
All code From what I've read, A1 & A2 are identical, but I don't if A3 is identical to A2. I know the code will compile since all of the A classes are tmemplated.
Note: All of the class & method declarations are in a .h file.
template <typename _Ty>
class A1 {
public:
A1();
void foo() { ... }
};
template <typename _Ty>
class A2 {
public:
A2();
void foo();
};
template <typename _Ty>
inline void A2<_Ty>::foo() { ... }
template <typename _Ty>
class A3 {
public:
A3();
void foo();
};
template <typename _Ty>
void A3<_Ty>::foo() { ... } // note: No inline keyword here.
P.S. I've seen variants of this question on stackoverflow, but not this exact question.
Yes, it's meaningful, but doesn't have much effect when combined with templates.
The major effect of the inline keyword is to tell the compiler that this function may appear with the same definition in multiple compilation units, so it needs to be flagged as "select-one" for the linker (so you don't get multiple definition errors). Templates already have this feature.
inline also is a hint to the compiler that you think the function should be inlined, but the compiler usually makes the final decision on inlining optimizations on its own.
Is inline keyword meaningful if function is defined in header file?
It is. Following project will produce linker error on both msvc and g++ BECAUSE of the omission of inline keyword:
main.cpp:
#include "a.h"
int main(int argc, char** argv){
A obj;
obj.f();
a();
b();
return 0;
}
a.h:
#ifndef A_HEADER
#define A_HEADER
class A{
public:
void f();
};
void a(){
}
void b();
void A::f(){
}
#endif
b.cpp:
#include "a.h"
void b(){
A obj;
obj.f();
a();
}
*.pro file (for Qt 4 build system):
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
HEADERS += a.h
SOURCES += b.cpp main.cpp
Compilation output:
cl.exe:
main.obj : error LNK2005: "void __cdecl a(void)" (?a##YAXXZ) already defined in b.obj
main.obj : error LNK2005: "public: void __thiscall A::f(void)" (?f#A##QAEXXZ) already defined in b.obj
debug\1234.exe : fatal error LNK1169: one or more multiply defined symbols found
g++:
debug/main.o: In function `Z1av':
D:\c++\1234/a.h:6: multiple definition of `a()'
debug/b.o:D:\c++\1234/a.h:6: first defined here
debug/main.o:D:\c++\1234/a.h:11: multiple definition of `A::f()'
debug/b.o:D:\c++\1234/a.h:11: first defined here
collect2: ld returned 1 exit status
make[1]: *** [debug/1234.exe] Error 1
make: *** [debug] Error 2
Now, why do you think this happens? Because compiler inserts contents of header file into *.cpp file when compiling. Since function isn't "inline", its name is made known to the linker, and each .obj/.o file will get its own unique copy of A::f() and a(). Linker won't know which you're supposed to use and will complain. If you make functions inline, everything will work fine.
However, templates are another story.