a.hpp:
#pragma once
struct S
{
static int v;
};
int S::v = 0;
b.hpp:
#pragma once
void addOne();
b.cpp:
#include "b.hpp"
#include "a.hpp"
void addOne()
{
S::v += 1;
}
main.cpp:
#include <iostream>
#include "a.hpp"
#include "b.hpp"
int main()
{
S::v = 2;
addOne();
S::v += 2;
std::cout << S::v << std::endl;
}
Does not work when compiling with g++ -std=c++14 main.cpp b.cpp && ./a.out (multiple definition of S::v).
However when I change the code to:
a.hpp:
#pragma once
struct S
{
template<typename T>
static int v;
};
template<typename T>
int S::v = 0;
and replace all S::v with S::v<void> it compiles and works how I intended the first example to work (outputs 5).
I believe I know why the first code example does not work: The int S::v = 0; line gets once compiled in the main.cpp unit and once in the b.cpp unit. When the linker links these two together, then the variable S::v gets essentially redefined.(?)
Why does the code with the template work?
Why does the code with the template work?
Essentially, because the standard says so.
With templates, the rules usually amoun to: "everyone using them must have their definition available." The exact same applies to static data members of class templates: a definition of such a static data member must be present in every translation unit in which it is odr-used. It's up to the compiler & linker to make sure this does not lead to errors.
Note that since C++17, you can solve the non-template case by making the static data member inline:
#pragma once
struct S
{
static inline int v = 0;
};
Related
I am trying to understand internal linking and external linking so I've tried this program:
// foo.h
static int x = 7; // makes x internally linked
void print();
// foo.cpp
#include "bar.h"
#include <iostream>
void func()
{
std::cout << x << '\n';
}
// bar.h
static int x = 5; // internally linked. without "static" itis linked externally
void func();
// bar.cpp
#include "bar.h"
#include <iostream>
void func()
{
std::cout << x << '\n';
}
// driver program
#include <iostream>
// forward declarations
void func();
void print();
int main()
{
func();
print();
}
I've removed inclusion guards (or #pagma once) for the sake of brevity. I also forward-declare func() and print() functions because if I include the headers they are defined in foo.h and bar.h then the compiler won't compile because of the redefinition of the object x.
When I run the program I always get always the same value from the two functions func and print although they reference a separate object x.
The output:
5
5
Normally print prints 7 because includes foo.h which is initializing its x object to 7.
I've declared x in both headers as static to be linked internally in the TU it is used otherwise if remove static from them then the two objects has external linking which causes the linker fail because of multiple definitions for the object x.
I tried your code but with foo.cpp as
#include "foo.h"
#include <iostream>
void print()
{
std::cout << x << '\n';
}
and the output is
5
7
as you expect, so I think that you have a typo in foo.cpp.
I am learning C++ and currently testing inline functions. If I run my code now I will have linking error, but if I change
inline void Test::print40()
to
void Test::print40()
everything would be fine. Could you explain to me why I have an error and how to use inline function in this case.
// main.cpp file
#include "Test.h"
using namespace std;
int main()
{
Test obj1;
obj1.print40();
}
// Test.cpp file
#include <iostream>
#include "Test.h"
inline void Test::print40()
{
std::cout << "40";
}
// Test.h file
#pragma once
class Test
{
public:
void print40();
};
Inline function definition shall be in each compilation unit where it is ODR used.
On the other hand in your project the compilation unit main does not know that the function is an inline function. So it can not find its definition.
Move this definition from Test.cpp
#pragma once
class Test
{
public:
void print40();
};
inline void Test::print40()
{
std::cout << "40";
}
to the header Test.h.
The module Test.cpp is redundant.
As the function is very simple and short then it could be defined in the class definition as for example
class Test
{
public:
void print40()
{
std::cout << "40";
}
};
In this case it will be an inline function by default.
I am trying to define a member struct of a class in a separate file. however, I not sure what is the correct way to implement it.
Below is what I have tried. in code1.cpp is the main source code. I would like to put the definition of the member struct, Mid, to a separate file, code2.cpp. However, in order for code2.cpp know the struct is part of TestCls, I import code1.cpp there and added the guards. I know this is not going to work but I am not sure how to make it work. Thanks
code1.cpp:
#include <iostream>
#include "code2.cpp"
class TestCls {
public:
struct Mid;
};
int main() {
TestCls::Mid mid1;
std::cout << mid1.a << std::endl;
}
code2.cpp
#ifndef XXX
#define XXX
#include <iostream>
#include <sys/dtrace.h>
#include "code1.cpp"
struct TestCls::Mid {
int a = 0;
};
#endif //XXX
Don't include cpp files. Only include header files. While headers files can technically have any (or no) suffix, using source file suffix may end up confusing a build system or compiler to think that it is supposed to be compiled, which you don't want to do with a header. .h or .hpp and few others are commonly used suffixes for headers.
Your code2.cpp includes code1.cpp and code1.cpp includes code2.cpp. Don't have recursive includes like this. While the include guard prevents infinite recursion, this can easily break in some cases.
For a small program like this, as an exercise, I recommend that you first write it entirely into a single file. For example, following would be correct:
class TestCls {
public:
struct Mid;
};
struct TestCls::Mid {
int a = 0;
};
#include <iostream>
int main() {
TestCls::Mid mid1;
std::cout << mid1.a << std::endl;
}
Now, you can slice the file into multiple ones while keeping the order.
// TestCls.hpp
#pragma once
class TestCls {
public:
struct Mid;
};
// TestClsMid.hpp
#pragma once
#include "TestCls.hpp"
struct TestCls::Mid {
int a = 0;
};
// main.cpp
#include "TestCls.hpp"
#include "TestClsMid.hpp"
#include <iostream>
int main() {
TestCls::Mid mid1;
std::cout << mid1.a << std::endl;
}
I used #pragma once for simplicity, buy you can opt for macro guards if you so prefer.
That said, I recommend to reconsider whehter there is any advantage in not defining TestCls::Mid in TestCls.hpp.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 4 years ago.
I simplify the problem. I wanna know why this can't compile:
Error message: undefined reference to 'Foo<int>::j'
a.h
#pragma once
template<typename T>
class Foo{
public:
int bar(){
return j;
}
private:
static int j;
};
a.cpp
#include "a.h"
template<typename T>
int Foo<T>::j = 3;
main.cpp
#include "a.h"
#include <iostream>
using namespace std;
int main() {
Foo<int> f;
cout << f.bar();
return 0;
}
Templates are the cause.
template<typename T>
int Foo<T>::j = 3;
doesn't get resolved for main.cpp as it has no information about a.cpp.
And as for a.cpp it doesn't create Foo as it isn't used there.
For the system to work, you'd need to add
int Foo<int>::j = 3;
to a.cpp or
template<typename T>
int Foo<T>::j = 3;
to main.cpp.
On the side note, maybe new usage of inline keyword in C++17 i what you are looking for.
Consider this code.
//header.h
int x;
//otherSource.cpp
#include "header.h"
//main.cpp
#include "header.h"
...
int main()
{
}
In this case compiler erred with the message. "fatal error LNK1169: one or more multiply defined symbols found"
but when I add static before x, it compiles without errors.
And here is the second case.
//header.h
class A
{
public:
void f(){}
static int a;
};
int A::a = 0;
/otherSource.cpp
#include "header.h"
//main.cpp
#include "header.h"
...
int main()
{
}
In this case compiler again erred with multiple declaration.
Can anybody explain me the behavior we static variables in classes and in global declarations?? Thanks in advance.
The issue with the static member variable is that you have the definition occur in the header file. If you #include the file in multiple source files, you have multiple definitions of the static member variable.
To fix this, the header file should consist only of this:
#ifndef HEADER_H
#define HEADER_H
// In the header file
class A
{
public:
void f(){}
static int a;
};
#endif
The definition of the static variable a should be in one and only one module. The obvious place for this is in your main.cpp.
#include "header.h"
int A::a = 0; // defined here
int main()
{
}
Declare x as extern in header.h to tell the compiler that x will be defined somewhere else:
extern int x;
Then define x once in the source file which you think is most fitting.
For example in otherSource.cpp:
int x = some_initial_value;