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(¬main_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 ¬main_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.
Related
Using Clang++ (v3.8.0), the following code fails to link due to sSomeValue being an undefined reference.
#include <iostream>
struct MyClass
{
static constexpr int sSomeSize = 3;
static constexpr int sSomeValue = 10;
};
int foo()
{
int someArray[MyClass::sSomeSize] = {};
std::fill(std::begin(someArray), std::end(someArray), MyClass::sSomeValue);
return someArray[0];
}
int main()
{
std::cout << foo() << std::endl;
}
More precisely:
clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
/tmp/main-c8de0c.o: In function `foo()':
main.cpp:(.text+0x2): undefined reference to `MyClass::sSomeValue'
/tmp/main-c8de0c.o: In function `main':
main.cpp:(.text+0x16): undefined reference to `MyClass::sSomeValue'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
However, changing the definition of foo to
int foo()
{
int someArray[MyClass::sSomeSize] = {MyClass::sSomeValue, MyClass::sSomeValue, MyClass::sSomeValue};
return someArray[0];
}
does not exhibit the same linker error, even though sSomeValue is still being used.
What is going on here? Is the compiler doing some optimization around the std::fill call that I may not be aware of?
Note that g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out compiles, links, and outputs 10 as expected with v6.3.0.
The error is nothing to do with std::fill.
If you refer below documentation, it says: Reference variables can be declared constexpr (their initializers have to be reference constant expressions):
http://en.cppreference.com/w/cpp/language/constexpr
Slight modification of your code works fine. Just make the struct variables "const &" as said above.
#include <iostream>
struct MyClass
{
static constexpr int const& sSomeSize = 3;
static constexpr int const& sSomeValue = 10;
};
int foo()
{
int someArray[MyClass::sSomeSize] = {};
std::fill(std::begin(someArray), std::end(someArray), MyClass::sSomeValue);
return someArray[0];
}
int main()
{
std::cout << foo() << std::endl;
}
Also refer here for well explained article about constexpr and static
"Does static constexpr variable make sense?
Specially the last para in ticked answer.
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(¬main_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 ¬main_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;
}
Using g++, when two compilation units "a1.o" and "a2.o" both define and use the same weak symbol, the linker will silently resolve to the first occurrence of the symbol wherever it is used. As a result, the behavior of the application will depend on the order of the object files on the linker command line. What can be done to ensure that these symbols are resolved locally to each compilation unit?
For instance, as a minimalist example, if I have the following source files:
a1.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar1() {A a; a.foo();}
a2.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar2() {A a; a.foo();}
main.cpp:
void bar1();
void bar2();
int main()
{
bar1();
bar2();
}
and compile them with:
for i in a1 a2 main ; do g++ -c -o $i.o $i.cpp ; done
The output will depend on the relative position of a1.o and a2.o on the linker command line:
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a1.cpp
g++ -o main main.o a{2,1}.o ; ./main
a2.cpp
a2.cpp
I'd like to get the same result as if using the '-fno-weak' command line option:
for i in a1 a2 main ; do g++ -fno-weak -c -o $i.o $i.cpp ; done
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a2.cpp
but '-fno-weak' seems to lead to other complications. What are the alternatives (besides not inlining and fixing collisions)?
For those wondering what could be a typical use case: when writing mock components it is sometimes convenient to have header-only implementations. Different test fixtures end-up having different mock implementations of the same component type, which becomes an issue when all the fixtures are linked into a single test runner.
You asked:
What are the alternatives (besides not inlining and fixing collisions)?
Use local namespaces or anonymous namespaces.
a1.cpp:
#include <iostream>
namespace A1_namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
using namespace A1_namespace;
void bar1() {A a; a.foo();}
or
#include <iostream>
namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
void bar1() {A a; a.foo();}
Make similar changes to a2.cpp.
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.
I have an application that loads a library with dlopen, it looks like this:
#include <iostream>
#include <dlfcn.h>
void foo()
{
std::cout << "foo";
}
int main()
{
void* libbar = dlopen("./libbar.so", RTLD_LAZY);
if (!libbar)
{
std::cerr << dlerror() << std::endl;
return 1;
}
void(*bar)() = (void(*)())dlsym(libbar, "bar");
if (!bar)
{
std::cerr << dlerror() << std::endl;
return 1;
}
bar();
dlclose(libbar);
}
And here is libbar:
#include <iostream>
void foo();
extern "C"
void bar()
{
foo();
std::cout << "bar" << std::endl;
}
Output:
./libbar.so: undefined symbol: _Z3foov
Expected output:
foobar
How to make foo visible to libbar?
I'm actually using C++ and the real problem is with undefined symbols from constructors/member functions, but this should be very similar. I'm working on Linux with GCC 4.7.
You should compile and link main.cc with
g++ -rdynamic -Wall main.cc -o prog -ldl
The -rdynamic flag is important at link time.
And you'll better declare extern "C" those functions which you want to pass to dlsym.
See also the Program Library HowTo.