How can achieve external linkage for class static functions when the compiler thinks the code is local linkage or inline?
Consider three files:
traits.h:
template <typename T>
struct Traits
{
static int InlineFunction(T);
static int Function(T);
};
traitsimp.cpp:
#include "traits.h"
template <>
struct Traits<int>
{
static int InlineFunction(int) { return 42; }
static int Function(int);
};
int Traits<int>::Function(int i) { return i; }
main.cpp:
#include "traits.h"
int main()
{
int result = Traits<int>::Function(5);
result = Traits<int>::InlineFunction(result);
return 0;
}
When compiled receives:
$ g++ traitsimp.cpp main.cpp -o traitstest
/tmp/cc6taAop.o: In function `main':
main.cpp:(.text+0x1b): undefined reference to `Traits<int>::InlineFunction(int)'
collect2: ld returned 1 exit status
How do I convince the compiler to give InlineFunction external linkage while still writing the function within the class definition?
I think you need to decide whether to have external linkage and define out of line or keep it inline and effectively just have internal linkage. Is there a reason not to define your Traits<int> in a header? Note that the full specialization is no longer a template, so there is really no difference to how it is handled versus a non-templated function.
Edited: Tried this in VS2010, and it may still not suit, but you could put code in traitsimp.cpp that takes the address of the method:
auto getAddress = &Traits<int>::InlineFunction;
This forces the method to get an address. I'm a bit rusty on whether this behaviour would be standard or not.
Related
I am attempting to use static constexpr arrays within a template specialised class as shown below:
///////////////////////////////////////////////////////////////////////////
struct good {
static constexpr int values[1] = { 0 };
};
constexpr int good::values[1];
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct bad;
template <>
struct bad<int> {
static constexpr int values[1] = { 0 };
};
constexpr int bad<int>::values[1];
///////////////////////////////////////////////////////////////////////////
int
main (int argc, char **argv)
{
#if 1
return good::values[0];
#else
return bad<int>::values[0];
#endif
}
I am aware of the requirement to both declare and define static members, and the 'good' case from above appears to succeed with gcc-6.2.0 and clang-3.9.0 using -std=c++1z.
However the 'bad' case results in an undefined reference under clang-3.9.0, giving the output as follows:
danny#steve ~/src $ clang++ -std=c++1z scratch.cpp
/tmp/scratch-56fa44.o: In function `main':
scratch.cpp:(.text+0x15): undefined reference to `bad<int>::values'
clang-3.9: error: linker command failed with exit code 1 (use -v to see invocation)
Is there something additional I need to do, or that I'm missing, to instantiate static constexpr members? The code appears to work fine when modified to use static const members.
The code will link successfully if the unit is instead compiled with -std=c++1y.
Is there something additional I need to do, or that I'm missing, to instantiate static constexpr members?
The code looks well formed, but it indeed fails to link in Clang up to version 5.0.2, however it is fully accepted in Clang 6.0. Demo: https://gcc.godbolt.org/z/Ka7W4bbqf
This suggests that it was just a compiler bug.
I tried to look this up, but did not find it anywhere. So here's the question:
Static functions in C/C++ can be used to "make them invisible to the outer world". Great, when having two same-named static functions in two different compiled units (.c files), it makes me sure that I call the right one. But can I also be sure that I call my local static function when there exists a same-named non-static function somewhere in the project or libraries? That is, does the static function locally hide the non-static one?
Sure I can test it (and I did) but I want to know whether this behaviour has fixed definition in C/C++. Thanks.
Edit: Simplified example code which caused unexpected behaviour to me. The question is about the fix of the problem (suppose I cannot change the library).
In mylib.c:
#include "mylib.h"
int send(void * data, int size);
...
int send(void * data, int size) {
return send_message(queueA, data, size);
}
void libfunc(void) {
send(str, strlen(str));
}
In mylib.h:
// only libfunc is declared here
void libfunc(void);
In myprog.c:
#include "mylib.h"
int send(void * data, int size);
...
int send(void * data, int size) {
return send_message(queueB, data, size);
}
void progfunc(void) {
// expected to send a message to queueB
// !!! but it was sent to queueA instead !!!
send(str, strlen(str));
}
Compiled mylib.c + further files -> mylib.a
Compiled myprog.c -> myprog.o
Linked myprog.o + mylib.a -> myprog
You'd get a compilation error because functions have default external linkage, thus the new static function would result in a conflict of linkage specifiers.
If the declaration of the non-static function isn't visible, the static one will be called:
void foo(); //external linkage
static void foo() {}; //internal linkage and error
It does not hide functions with same name declared in the same scope. However you may not have a function with the same signature declared as having internal and external linkage.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
undefined reference to static member variable
What is an undefined reference/unresolved external symbol error and how do I fix it?
#include<iostream>
using namespace std;
class abc {
private:
static int a ;
public:
abc(int x) {
a = x;
}
void showData() {
cout<<"A = "<<a<<endl;
}
};
int main() {
abc a1(4);
abc a2(5);
a1.showData();
a2.showData();
return 0;
}
When I try to compile this function on Ubuntu with GCC compiler. I get the following error.
/tmp/ccCKK2YN.o: In function `main':
static1.cpp:(.text+0xb): undefined reference to `Something::s_nValue'
static1.cpp:(.text+0x14): undefined reference to `Something::s_nValue'
collect2: ld returned 1 exit status
Compilation failed.
Where as the following code runs fine
#include<iostream>
using namespace std;
class Something
{
public:
static int s_nValue;
};
int Something::s_nValue = 1;
int main()
{
Something cFirst;
cFirst.s_nValue = 2;
Something cSecond;
std::cout << cSecond.s_nValue;
return 0;
}
Is this because Static member variables needs to initialized explicitly before accessing them via objects.Why so ?
static int s_nValue; doesn't allocate any storage to store the int, it just declares it.
You allocate somewhere in memory to store the variable with:
int Something::a=0;
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope.
See this thread.
In short, the static member needs to be initialized somewhere in a .cpp file so that the compiler allocates space for it. The declaration would look like this:
int abc::a = 0;
That happens because since static members are shared between all instances of a class, they need to be declared in one single place.
If you define the static variable inside the class declaration then each include to that file would have a definition to that variable (which is against to the static meaning).
Because of that you have to define the static members in the .cpp.
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.
I am baffled by the linker error when using the following code:
// static_const.cpp -- complete code
#include <vector>
struct Elem {
static const int value = 0;
};
int main(int argc, char *argv[]) {
std::vector<Elem> v(1);
std::vector<Elem>::iterator it;
it = v.begin();
return it->value;
}
However, this fails when linking -- somehow it needs to have a symbol for the static const "value."
$ g++ static_const.cpp
/tmp/ccZTyfe7.o: In function `main':
static_const.cpp:(.text+0x8e): undefined reference to `Elem::value'
collect2: ld returned 1 exit status
BTW, this compiles fine with -O1 or better; but it still fails for more complicated cases. I am using gcc version 4.4.4 20100726 (Red Hat 4.4.4-13).
Any ideas what might be wrong with my code?
If you want to initialize it inside the struct, you can do it too:
struct Elem {
static const int value = 0;
};
const int Elem::value;
Try writing it as
struct Elem {
static const int value;
};
const int Elem::value = 0;
etc
.
static class members are generally supposed to be defined outside the class (declared inside, defined outside) in one compilation unit.
I don't remember how that interacts with inline initialization of const static integral members.
Also see this post: essentially, the problem is that somehow compiler ends up expanding your code into taking the address of Elem::value.
Why not just do this?
return Elem::value;
But the answer is that you are assigning a value in the declaration. This is supposed to work for basic types such as int, and is only required for complex types (i.e. classes, such as if you had a string instead of int). What I have found in practice is that this is hit or miss depending on what version of what compiler you are using. And, as you found out, which optimization level.
In most of the compilers defining in-class static const <integral type> works fine. But some compilers like Android NDK, such in-class definitions results in linker errors. For such case, we may use the typed enums:
struct X
{
enum : int64_t { VALUE = 100; }; // == static const int64_t VALUE = 100;
};