How to declare constexpr extern? - c++

Is it possible to declare a variable extern constexpr and define it in another file?
I tried it but the compiler gives error:
Declaration of constexpr variable 'i' is not a definition
in .h:
extern constexpr int i;
in .cpp:
constexpr int i = 10;

no you can't do it, here's what the standard says (section 7.1.5):
1 The constexpr specifier shall be applied only to the definition of a
variable or variable template, the declaration of a function or
function template, or the declaration of a static data member of a
literal type (3.9). If any declaration of a function, function
template, or variable template has a constexpr specifier, then all its
declarations shall contain the constexpr specifier. [Note: An explicit
specialization can differ from the template declaration with respect
to the constexpr specifier. Function parameters cannot be declared
constexpr. — end note ]
some examples given by the standard:
constexpr void square(int &x); // OK: declaration
constexpr int bufsz = 1024; // OK: definition
constexpr struct pixel { // error: pixel is a type
int x;
int y;
constexpr pixel(int); // OK: declaration
};
extern constexpr int memsz; // error: not a definition

C++17 inline variables
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(&notmain_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return &notmain_i;
}
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
The C++ standard guarantees that the addresses will be the same. C++17 N4659 standard draft
10.1.6 "The inline specifier":
6 An inline function or variable with external linkage shall have the same address in all translation units.
cppreference https://en.cppreference.com/w/cpp/language/inline explains that if static is not given, then it has external linkage.
See also: How do inline variables work?
Tested in GCC 7.4.0, Ubuntu 18.04.

What you probably want is extern and constexpr initialization, e.g.:
// in header
extern const int g_n;
// in cpp
constexpr int g_n = 2;
This is support though in Visual Studio 2017 only through conformance mode:
/Zc:externConstexpr (Enable extern constexpr variables)
constexpr definition of extern const variable

No. Extern constexpr does not make any sense. Please read http://en.cppreference.com/w/cpp/language/constexpr
i.e. the bit
it must be immediately constructed or assigned a value.

I agree with 'swang' above, but there is a consequence. Consider:
ExternHeader.hpp
extern int e; // Must be extern and defined in .cpp otherwise it is a duplicate symbol.
ExternHeader.cpp
#include "ExternHeader.hpp"
int e = 0;
ConstexprHeader.hpp
int constexpr c = 0; // Must be defined in header since constexpr must be initialized.
Include1.hpp
void print1();
Include1.cpp
#include "Include1.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>
void print1() {
std::cout << "1: extern = " << &e << ", constexpr = " << &c << "\n";
}
Include2.hpp
void print2();
Include2.cpp
#include "Include2.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>
void print2() {
std::cout << "2: extern = " << &e << ", constexpr = " << &c << "\n";
}
main.cpp
#include <iostream>
#include "Include1.hpp"
#include "Include2.hpp"
int main(int argc, const char * argv[]) {
print1();
print2();
return 0;
}
Which prints:
1: extern = 0x1000020a8, constexpr = 0x100001ed0
2: extern = 0x1000020a8, constexpr = 0x100001ed4
IE the constexpr is allocated twice whereas the extern is allocated once.
This is counterintuitive to me, since I 'expect' constexpr to be more optimized than extern.
Edit: const and constexpr have the same behaviour, with regard to allocation, therefore from that point of view the behaviour is as expected. Though, as I said, I was surprised when I came across the behaviour of constexpr.

Yes it somewhat is...
//===================================================================
// afile.h
#ifndef AFILE
#define AFILE
#include <cstddef>
#include <iostream>
enum class IDs {
id1,
id2,
id3,
END
};
// This is the extern declaration of a **constexpr**, use simply **const**
extern const int ids[std::size_t(IDs::END)];
// These functions will demonstrate its usage
template<int id> void Foo() { std::cout << "I am " << id << std::endl; }
extern void Bar();
#endif // AFILE
//===================================================================
// afile.cpp
#include "afile.h"
// Here we define the consexpr.
// It is **constexpr** in this unit and **const** in all other units
constexpr int ids[std::size_t(IDs::END)] = {
int(IDs::id1),
int(IDs::id2),
int(IDs::id3)
};
// The Bar function demonstrates that ids is really constexpr
void Bar() {
Foo<ids[0] >();
Foo<ids[1] + 123>();
Foo<ids[2] / 2 >();
}
//===================================================================
// bfile.h
#ifndef BFILE
#define BFILE
// These functions will demonstrate usage of constexpr ids in an extern unit
extern void Baz();
extern void Qux();
#endif // BFILE
//===================================================================
// bfile.cpp
#include "afile.h"
// Baz demonstrates that ids is (or works as) an extern field
void Baz() {
for (int i: ids) std::cout << i << ", ";
std::cout << std::endl;
}
// Qux demonstrates that extern ids cannot work as constexpr, though
void Qux() {
#if 0 // changing me to non-0 gives you a compile-time error...
Foo<ids[0]>();
#endif
std::cout << "Qux: 'I don't see ids as consexpr, indeed.'"
<< std::endl;
}
//===================================================================
// main.cpp
#include "afile.h"
#include "bfile.h"
int main(int , char **)
{
Bar();
Baz();
Qux();
return 0;
}

Related

private static data member + template class [duplicate]

What is the best way to initialize a private, static data member in C++? I tried this in my header file, but it gives me weird linker errors:
class foo
{
private:
static int i;
};
int foo::i = 0;
I'm guessing this is because I can't initialize a private member from outside the class. So what's the best way to do this?
The class declaration should be in the header file (Or in the source file if not shared).
File: foo.h
class foo
{
private:
static int i;
};
But the initialization should be in source file.
File: foo.cpp
int foo::i = 0;
If the initialization is in the header file then each file that includes the header file will have a definition of the static member. Thus during the link phase you will get linker errors as the code to initialize the variable will be defined in multiple source files.
The initialisation of the static int i must be done outside of any function.
Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const integer type (bool, char, char8_t [since C++20], char16_t, char32_t, wchar_t, short, int, long, long long, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants.). You can then declare and initialize the member variable directly inside the class declaration in the header file:
class foo
{
private:
static int const i = 42;
};
For a variable:
foo.h:
class foo
{
private:
static int i;
};
foo.cpp:
int foo::i = 0;
This is because there can only be one instance of foo::i in your program. It's sort of the equivalent of extern int i in a header file and int i in a source file.
For a constant you can put the value straight in the class declaration:
class foo
{
private:
static int i;
const static int a = 42;
};
Since C++17, static members may be defined in the header with the inline keyword.
http://en.cppreference.com/w/cpp/language/static
"A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify a default member initializer. It does not need an out-of-class definition:"
struct X
{
inline static int n = 1;
};
For future viewers of this question, I want to point out that you should avoid what monkey0506 is suggesting.
Header files are for declarations.
Header files get compiled once for every .cpp file that directly or indirectly #includes them, and code outside of any function is run at program initialization, before main().
By putting: foo::i = VALUE; into the header, foo:i will be assigned the value VALUE (whatever that is) for every .cpp file, and these assignments will happen in an indeterminate order (determined by the linker) before main() is run.
What if we #define VALUE to be a different number in one of our .cpp files? It will compile fine and we will have no way of knowing which one wins until we run the program.
Never put executed code into a header for the same reason that you never #include a .cpp file.
Include guards (which I agree you should always use) protect you from something different: the same header being indirectly #included multiple times while compiling a single .cpp file.
With a Microsoft compiler[1], static variables that are not int-like can also be defined in a header file, but outside of the class declaration, using the Microsoft specific __declspec(selectany).
class A
{
static B b;
}
__declspec(selectany) A::b;
Note that I'm not saying this is good, I just say it can be done.
[1] These days, more compilers than MSC support __declspec(selectany) - at least gcc and clang. Maybe even more.
int foo::i = 0;
Is the correct syntax for initializing the variable, but it must go in the source file (.cpp) rather than in the header.
Because it is a static variable the compiler needs to create only one copy of it. You have to have a line "int foo:i" some where in your code to tell the compiler where to put it otherwise you get a link error. If that is in a header you will get a copy in every file that includes the header, so get multiply defined symbol errors from the linker.
If you want to initialize some compound type (f.e. string) you can do something like that:
class SomeClass {
static std::list<string> _list;
public:
static const std::list<string>& getList() {
struct Initializer {
Initializer() {
// Here you may want to put mutex
_list.push_back("FIRST");
_list.push_back("SECOND");
....
}
}
static Initializer ListInitializationGuard;
return _list;
}
};
As the ListInitializationGuard is a static variable inside SomeClass::getList() method it will be constructed only once, which means that constructor is called once. This will initialize _list variable to value you need. Any subsequent call to getList will simply return already initialized _list object.
Of course you have to access _list object always by calling getList() method.
C++11 static constructor pattern that works for multiple objects
One idiom was proposed at: https://stackoverflow.com/a/27088552/895245 but here goes a cleaner version that does not require creating a new method per member.
main.cpp
#include <cassert>
#include <vector>
// Normally on the .hpp file.
class MyClass {
public:
static std::vector<int> v, v2;
static struct StaticConstructor {
StaticConstructor() {
v.push_back(1);
v.push_back(2);
v2.push_back(3);
v2.push_back(4);
}
} _staticConstructor;
};
// Normally on the .cpp file.
std::vector<int> MyClass::v;
std::vector<int> MyClass::v2;
// Must come after every static member.
MyClass::StaticConstructor MyClass::_staticConstructor;
int main() {
assert(MyClass::v[0] == 1);
assert(MyClass::v[1] == 2);
assert(MyClass::v2[0] == 3);
assert(MyClass::v2[1] == 4);
}
GitHub upstream.
Compile and run:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
See also: static constructors in C++? I need to initialize private static objects
Tested on Ubuntu 19.04.
C++17 inline variable
Mentioned at: https://stackoverflow.com/a/45062055/895245 but here is a multifile runnable example to make it even clearer: How do inline variables work?
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr: How to declare constexpr extern?
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(&notmain_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return &notmain_i;
}
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
I don't have enough rep here to add this as a comment, but IMO it's good style to write your headers with #include guards anyway, which as noted by Paranaix a few hours ago would prevent a multiple-definition error. Unless you're already using a separate CPP file, it's not necessary to use one just to initialize static non-integral members.
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo
{
private:
static bar i;
};
bar foo::i = VALUE;
#endif
I see no need to use a separate CPP file for this. Sure, you can, but there's no technical reason why you should have to.
You can also include the assignment in the header file if you use header guards. I have used this technique for a C++ library I have created. Another way to achieve the same result is to use static methods. For example...
class Foo
{
public:
int GetMyStatic() const
{
return *MyStatic();
}
private:
static int* MyStatic()
{
static int mStatic = 0;
return &mStatic;
}
}
The above code has the "bonus" of not requiring a CPP/source file. Again, a method I use for my C++ libraries.
The linker problem you encountered is probably caused by:
Providing both class and static member definition in header file,
Including this header in two or more source files.
This is a common problem for those who starts with C++. Static class member must be initialized in single translation unit i.e. in single source file.
Unfortunately, the static class member must be initialized outside of the class body. This complicates writing header-only code, and, therefore, I am using quite different approach. You can provide your static object through static or non-static class function for example:
class Foo
{
// int& getObjectInstance() const {
static int& getObjectInstance() {
static int object;
return object;
}
void func() {
int &object = getValueInstance();
object += 5;
}
};
I follow the idea from Karl. I like it and now I use it as well.
I've changed a little bit the notation and add some functionality
#include <stdio.h>
class Foo
{
public:
int GetMyStaticValue () const { return MyStatic(); }
int & GetMyStaticVar () { return MyStatic(); }
static bool isMyStatic (int & num) { return & num == & MyStatic(); }
private:
static int & MyStatic ()
{
static int mStatic = 7;
return mStatic;
}
};
int main (int, char **)
{
Foo obj;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
obj.GetMyStaticVar () = 3;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
int valMyS = obj.GetMyStaticVar ();
int & iPtr1 = obj.GetMyStaticVar ();
int & iPtr2 = valMyS;
printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}
this outputs
mystatic value 7
mystatic value 3
is my static 1 0
Also working in privateStatic.cpp file :
#include <iostream>
using namespace std;
class A
{
private:
static int v;
};
int A::v = 10; // possible initializing
int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}
// g++ privateStatic.cpp -o privateStatic && ./privateStatic
What about a set_default() method?
class foo
{
public:
static void set_default(int);
private:
static int i;
};
void foo::set_default(int x) {
i = x;
}
We would only have to use the set_default(int x) method and our static variable would be initialized.
This would not be in disagreement with the rest of the comments, actually it follows the same principle of initializing the variable in a global scope, but by using this method we make it explicit (and easy to see-understand) instead of having the definition of the variable hanging there.
One "old-school" way to define constants is to replace them by a enum:
class foo
{
private:
enum {i = 0}; // default type = int
enum: int64_t {HUGE = 1000000000000}; // may specify another type
};
This way doesn't require providing a definition, and avoids making the constant lvalue, which can save you some headaches, e.g. when you accidentally ODR-use it.
Here are all possibilities and errors in one simple example ...
#ifndef Foo_h
#define Foo_h
class Foo
{
static const int a = 42; // OK
static const int b {7}; // OK
//static int x = 42; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
//static int y {7}; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
static int x;
static int y;
int m = 42;
int n {7};
};
// Foo::x = 42; // error: 'int Foo::x' is private
int Foo::x = 42; // OK in Foo.h if included in only one *.cpp -> *.o file!
int Foo::y {7}; // OK
// int Foo::y {7}; // error: redefinition of 'int Foo::y'
// ONLY if the compiler can see both declarations at the same time it,
// OTHERWISE you get a linker error
#endif // Foo_h
But better place this in Foo.cpp. This way you can separately compile each file and link them later, otherwise Foo:x will be present in multiple object files and cause a linker error. ...
// Foo::x = 42; // error: 'int Foo::x' is private, bad if Foo::X is public!
int Foo::x = 42; // OK in Foo.h if included in only one *.cpp -> *.o file!
int Foo::y {7}; // OK
Does this serves your purpose?
//header file
struct MyStruct {
public:
const std::unordered_map<std::string, uint32_t> str_to_int{
{ "a", 1 },
{ "b", 2 },
...
{ "z", 26 }
};
const std::unordered_map<int , std::string> int_to_str{
{ 1, "a" },
{ 2, "b" },
...
{ 26, "z" }
};
std::string some_string = "justanotherstring";
uint32_t some_int = 42;
static MyStruct & Singleton() {
static MyStruct instance;
return instance;
}
private:
MyStruct() {};
};
//Usage in cpp file
int main(){
std::cout<<MyStruct::Singleton().some_string<<std::endl;
std::cout<<MyStruct::Singleton().some_int<<std::endl;
return 0;
}
I just wanted to mention something a little strange to me when I first encountered this.
I needed to initialize a private static data member in a template class.
in the .h or .hpp, it looks something like this to initialize a static data member of a template class:
template<typename T>
Type ClassName<T>::dataMemberName = initialValue;

Compiler error or correct behavior for static const member variable, variadic templates, and &&?

I have noticed a strange behavior when trying to compile the code included below. I have 4 files as follows
createshared.h:
#ifndef CREATESHARED_H_
#define CREATESHARED_H_
#include <memory>
#include <utility>
#ifdef USE_REFREF
template<typename T, typename... Args>
std::shared_ptr<T> create_shared(Args&&... args)
{
class HelperClass : public T
{
public:
HelperClass (Args&& ... nargs) : T(std::forward<Args...>(nargs)...) {}
virtual ~HelperClass() = default;
};
return std::make_shared<HelperClass>(std::forward<Args...>(args)...);
}
#else
template<typename T, typename... Args>
std::shared_ptr<T> create_shared(Args... args)
{
class HelperClass : public T
{
public:
HelperClass (Args ... nargs) : T(nargs...) {}
virtual ~HelperClass() = default;
};
return std::make_shared<HelperClass>(args...);
}
#endif
#endif
staticinitclass.h
#ifndef STATICINITCLASS_H_
#define STATICINITCLASS_H_
class StaticInitClass
{
public:
#ifdef INITIALIZE_IN_HEADER
static const int default_i = 1;
#else
static const int default_i;
#endif
virtual ~StaticInitClass() = default;
StaticInitClass() = delete;
protected:
StaticInitClass(int i);
};
#endif
staticinitclass.cpp:
#include "staticinitclass.h"
#include <iostream>
#ifndef INITIALIZE_IN_HEADER
const int StaticInitClass::default_i = 2;
#endif
StaticInitClass::StaticInitClass(int i)
{
std::cout << "Created with " << i << std::endl;
}
main.cpp:
#include "staticinitclass.h"
#include "createshared.h"
#include <memory>
int main(int argc, const char* argv[])
{
auto shared = create_shared<StaticInitClass>(StaticInitClass::default_i);
}
With no flags, the program compiles and runs fine.
$ g++ -std=c++11 main.cpp staticinitclass.cpp
$ ./a.out
Created with 2
Fine, because default_i is an integral type, we can initialize it in the header. Let's do that
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DINITIALIZE_IN_HEADER
$ ./a.out
Created with 1
Good, still compiles and works fine. Now, let's add our && and std::forward
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DINITIALIZE_IN_HEADER -DUSE_REFREF
/tmp/cc3G4tjc.o: In function `main':
main.cpp:(.text+0xaf): undefined reference to `StaticInitClass::default_i'
collect2: error: ld returned 1 exit status
Linker error. Well, let's now try initializing our default_i member in the .cpp
$ g++ -std=c++11 main.cpp staticinitclass.cpp -DUSE_REFREF
$ ./a.out
Created with 2
And it works again. Using clang yields the same result, which would lead me to believe that this isn't just an isolated compiler error, but perhaps something in the language itself that prevents the static initialization. I just can't seem to connect why adding && would cause the break.
Currently I am using g++ 4.8.2 and clang++ 3.5 on Ubuntu 14.04
Any ideas what is broken here when using -DINITIALIZE_IN_HEADER and -DUSE_REFREF?
Following §9.4.2 [class.static.data]:
3 If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment expression is a constant expression (5.19). [...] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.
In other words, giving a const static data member a value directly in a header does not mean you don't need to define that data member. You should have this in staticinitclass.cpp file:
#ifndef INITIALIZE_IN_HEADER
const int StaticInitClass::default_i = 2;
#else
const int StaticInitClass::default_i; // this is what you don't have
#endif
Binding to a reference (to a forwarding reference && in your case deduced as const lvalue reference) counts as odr-use of this data member.
In case you don't use a forwarding reference and you take the argument by-value, then it is not an odr-use of that static data member, therefore no linker error is raised.

constexpr different exception specifier when splitting definition and declaration

I have the following test piece of code tested on gcc 4.7.2:
#include <iostream>
#include <type_traits>
#ifdef REMOVE_CONSTEXPR_NOEXCEPT
# define CONSTEXPR_NOEXCEPT
#else
# define CONSTEXPR_NOEXCEPT noexcept
#endif
class ConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static constexpr unsigned int Int(unsigned int i) CONSTEXPR_NOEXCEPT
#ifndef SPLIT_CONSTEXPR_DECLARATION
{
return i;
}
#else
;
#endif
};
#ifdef SPLIT_CONSTEXPR_DECLARATION
constexpr unsigned int ConstExpr::Int(unsigned int i) CONSTEXPR_NOEXCEPT {
return i;
}
#endif
class NoConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static unsigned int Int(unsigned int i) noexcept;
};
// It's OK on normal functions
inline unsigned int NoConstExpr::Int(unsigned int i) noexcept {
return i;
}
int main()
{
std::cout << "ConstExpr: " << std::integral_constant<unsigned int,
ConstExpr::Int(5)>::value << std::endl;
std::cout << "NoConstExpr: " << NoConstExpr::Int(5) << std::endl;
}
I get the following compilation output:
[matt test] g++ -std=c++11 main.cpp && ./a.out
ConstExpr: 5
NoConstExpr: 5
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION && ./a.out
main.cpp:28:55: error: declaration of ‘static constexpr unsigned int ConstExpr::Int(unsigned int)’ has a different exception specifier
main.cpp:17:33: error: from previous declaration ‘static constexpr unsigned int ConstExpr::Int(unsigned int) noexcept (true)’
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION -DREMOVE_CONSTEXPR_NOEXCEPT && ./a.out
ConstExpr: 5
NoConstExpr: 5
So my question is: Is it part of the C++11 spec to be able to split the definition and declaration of constexpr functions or is this a gcc bug?
Looks like the gcc bug solves this in 4.8.1

Unique address for constexpr variable

Is it possible to have a unique address allocated for a constexpr variable, i.e. the same for all translation units where the variable is available (usually through a header)? Consider the following example:
// foo.hh
#include <iostream>
constexpr int foo = 42;
// a.cc
#include "foo.hh"
void a(void) { std::cout << "a: " << &foo << std::endl; }
// b.cc
#include "foo.hh"
extern void a(void);
int main(int argc, char** argv) {
a();
std::cout << "b: " << &foo << std::endl;
}
Compiling a.cc and b.cc separately, and linking them together using gcc 4.7, I see two different addresses printed. If I add the keyword extern in the header, I get a linker error duplicate symbol _foo in: a.o and b.o which I find kind of surprising, because I thought that adding extern would more likely cause the compiler to import that symbol from another object instead of exporting it from the current object. But it seems my understanding of how things work was wrong here.
Is there a reasonable way to have a constexpr declared in one header, such that all translation units can use it in their constant expressions, and such that all translation units agree as to the address of that symbol? I would expect some additional code to denote the single translation unit where this symbol actually belongs to, just like with extern and non-extern variables without constexpr.
If you need to take the address of constexpr variable, declare it as a static member variable. It can be used as a constant expression this way (as opposed to using a function returning a const).
foo.h:
#ifndef FOO_H
#define FOO_H
struct Foo {
static constexpr int foo { 42 }; // declaration
};
#endif // FOO_H
foo.cpp:
#include "foo.hpp"
constexpr int Foo::foo; // definition
bar.cpp:
#include "foo.hpp"
const int* foo_addr() {
return &Foo::foo;
}
int foo_val() {
return Foo::foo;
}
main.cpp:
#include <iostream>
#include "foo.hpp"
extern const int* foo_addr();
extern int foo_val();
constexpr int arr[Foo::foo] {}; // foo used as constant expression
int main() {
std::cout << foo_addr() << " = " << foo_val() << std::endl;
std::cout << &Foo::foo << " = " << Foo::foo << std::endl;
}
Output:
$ g++ -std=c++11 foo.cpp bar.cpp main.cpp -o test && ./test
0x400a44 = 42
0x400a44 = 42
C++17 inline variables
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr: How to declare constexpr extern?
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(&notmain_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return &notmain_i;
}
Compile and run:
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
See also: How do inline variables work?
C++ standard on inline variables
The C++ standard guarantees that the addresses will be the same. C++17 N4659 standard draft
10.1.6 "The inline specifier":
6 An inline function or variable with external linkage shall have the same address in all translation units.
cppreference https://en.cppreference.com/w/cpp/language/inline explains that if static is not given, then it has external linkage.
Inline variable implementation
We can observe how it is implemented with:
nm main.o notmain.o
which contains:
main.o:
U _GLOBAL_OFFSET_TABLE_
U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i
notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i
and man nm says about u:
"u" The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process
there is just one symbol with this name and type in use.
so we see that there is a dedicated ELF extension for this.
I think constexpr is meant more for functions whose return value is constant. You can bind a constant variable to the return value of a constexpr function and expose that externally instead. For example:
// constexpr.h
#ifndef __CONSTEXPR_H
#define __CONSTEXPR_H
extern const int foo;
#endif // __CONSTEXPR_H
// constexpr.cpp
#include "constexpr.h"
constexpr int foo_expr()
{
return 42;
}
const int foo = foo_expr();
// unit1.cpp
#include <iostream>
#include "constexpr.h"
void unit1_print_foo()
{
std::cout << &foo << " = " << foo << std::endl;
}
// unit2.cpp
#include <iostream>
#include "constexpr.h"
void unit2_print_foo()
{
std::cout << &foo << " = " << foo << std::endl;
}
// main.cpp
extern void unit1_print_foo();
extern void unit2_print_foo();
int main(int, char**)
{
unit1_print_foo();
unit2_print_foo();
}
My result is:
$ g++-4.7 -std=c++11 constexpr.cpp unit1.cpp unit2.cpp main.cpp -o test && ./test
0x400ae4 = 42
0x400ae4 = 42
However, it should usually be sufficient to make the foo_expr function itself externally visible, and callers would use foo_expr() to get the value instead of treating it like a variable.

Undefined reference when using extern on a c++ object, but not integral type

I'm getting undefined reference errors when trying to use extern on a c++ object. It doesn't appear to happen with integral types. What am I missing?! This code below replicates the problem:
file1.cpp:
#include <string>
const std::string s("test");
int i = 99;
int main()
{
extern void Test();
Test();
}
file2.cpp:
#include <iostream>
#include <string>
extern const std::string s;
extern int i;
void Test()
{
std::cout << s << std::endl;
std::cout << i << std::endl;
}
if i comment out the usage of the 's' std::string variable, the linking errors go away.
There are other questions on SO similar to this, but they all seem to be related to people not defining the variable, which I am!
It's the const on std::string, it gives s internal linkage. Quote from [3.5 Program and linkage]:3:
A name having namespace scope (3.3.6) has internal linkage if it is
the name of
— a variable that is explicitly declared const or constexpr and
neither explicitly declared extern nor previously declared to have
external linkage; or
If you remove const, it works in vc++, and if you define them both extern const, it also works.
// file1.cpp
extern const std::string s("test");
extern const int i = 99;
// file2.cpp
extern const std::string s;
extern const int i;
If you remove any 'extern' from file1.cpp, it can't compile. If the variables are defined const, you can remove 'extern' from file1.cpp.