Forward declaring static C struct instances in C++ - c++

I'm writing a code generator, well, actually a data generator that will produce data structures of this form (obviously the actual data structures are much more elaborate):
typedef struct Foo {
int a;
struct Foo* foo;
} Foo;
extern Foo f1;
extern Foo f2;
Foo f1 = {1, &f2};
Foo f2 = {2, &f1};
This is portable for all C and C++ compilers I have tried.
I would like to forward declare these struct instances as static so as not to pollute the global variable space, as in:
typedef struct Foo {
int a;
struct Foo* foo;
} Foo;
static Foo f1;
static Foo f2;
static Foo f1 = {1, &f2};
static Foo f2 = {2, &f1};
Although this works with gcc and probably all C compilers, the above code does not work with C++ compilers and results in a compile error:
error: redefinition of ‘Foo f1’
error: ‘Foo f1’ previously declared
I understand why this is happening in C++. Is there a simple workaround that does not involve using code at runtime to achieve the same effect that is portable to all C++ compilers without resorting to using a C compiler to compile certain files?

This should compile with either C or C++ and give you the same name to access the same thing in both compilers.
#ifdef __cplusplus
namespace // use anonymous namespace to avoid poluting namespace.
{
struct StaticFoos
{
static Foo f1;
static Foo f2;
};
Foo StaticFoos::f1 = {1, &StaticFoos::f2};
Foo StaticFoos::f2 = {2, &StaticFoos::f1};
}
static const &Foo f1 = StaticFoos::f1;
static const &Foo f2 = StaticFoos::f2;
#else
static Foo f1 = {1, &f2_};
static Foo f2 = {1, &f1_};
#endif
Now in C and C++, you can access f1 and f2.

This seems to have a similar effect to Josh's answer, but with less complexity:
#ifdef __cplusplus
namespace {
extern Foo f1;
extern Foo f2;
Foo f1 = {1, &f2};
Foo f2 = {2, &f1};
}
#else
static Foo f1;
static Foo f2;
Foo f1 = {1, &f2};
Foo f2 = {2, &f1};
#endif
When compiled for C++, the extern definitions for f1 and f2 are exposed in the object file with an externally linkable symbol; however, because they are inside an anonymous namespace the symbols are mangled in such a way that they will not conflict with symbols from another translation unit.
With macro magic you could set things up so there's only one place where f1 and f2 are declared and defined, but if this is being generated mechanically there's probably not much reason to do that.
Something like:
#ifdef __cplusplus
#define START_PRIVATES namespace {
#define END_PRIVATES }
#define PRIVATE extern
#else
#define START_PRIVATES
#define END_PRIVATES
#define PRIVATE static
#endif
START_PRIVATES
PRIVATE Foo f1;
PRIVATE Foo f2;
Foo f1 = {1, &f2};
Foo f2 = {2, &f1};
END_PRIVATES

What you are trying to avoid is termed as Static Initialization Order Fiasco. You will be well served to use functions instead and also to initialize the individual objects with default values and then reseat the member pointers.
Your code samples mean radically different things. You will have to relook. The first one succeeds because you have a definition of one object and a declaration of another. This will work with both C and C++.
extern Foo f1;
This is a declaration and a tentative definition.
static Foo f1;
This is the declaration and definition of an object f1 of type struct Foo.
static Foo f2;
Ditto.
static Foo f1 = {1, &f2};
This is a redefinition. You have violated the One Definition Rule which says, there must be one and exactly one definition of a symbol in a translation unit. Outside of that you are allowed to have multiple definitions but of course each such occurrence has to have the same syntax and semantics.
static Foo f2 = {2, &f1};
Ditto.
extern Foo fn;
/* some code */
extern Foo fn;
/* some more ... */
Foo fn; /* finally a definition */
This is fine since it's ok to have multiple tentative declarations.

You can't forward declare objects, only types. The extern solution is the correct solution. Or if you really need to avoid global namespace pollution, make them static and initialize them using a function which you call before all others.
EDIT: Michael Burr mentioned the reason in a comment, I figured I'd add it to a post:
#dirkgently: it is valid C because the
C standard says: "Within one
translation unit, each declaration of
an identifier with internal linkage
denotes the same object or function".
C++ has no such rule.
EDIT:
As noted in one other post. You can use an anonymous namespace as well to limit the scope of the variable. Just wrap the namespace stuff in an #ifdef __cplusplus and you should be good to go.

I have encountered this problem. The restriction is frustrating and I don't see any reason why C++ has this gratuitous incompatibility with C.
My solution is to use static functions - which you can forward declare - which just return f1 and f2:
typedef struct Foo {
int a;
struct Foo* foo;
} Foo;
static Foo* link_f1();
static Foo* link_f2();
static Foo f1 = {1, link_f2()};
static Foo f2 = {2, link_f1()};
static Foo* link_f1() { return &f1; }
static Foo* link_f2() { return &f2; }
Unfortunately this isn't valid C so you'll still need different code for C and C++.

I would create two files (.cpp and .h):
code.h:
typedef struct Foo {
Foo() {}
Foo(int aa, struct Foo* ff) : a(aa), foo(ff) {}
int a;
struct Foo* foo;
} Foo;
static Foo f1;
static Foo f2;
code.cpp:
void myfun()
{
f1 = Foo(1, &f2);
f2 = Foo(2, &f1);
}
I would also prefer to put all variables like f1, f2 ... into some kind of "storage" object (of my own class or e.g. some STL container). Then, I would define this object as a static one.

Here is what I did in my project. Instead of trying to solve this with an anonymous namespace, I used a named namespace.
[ And then thanks to Matt McNabb's helpful comments, it turns out that an anonymous namespace will do for a super tidy solution with fewer macros that generates no external name pollution. ]
This allows me to have two separate regions of program text, with regular file scope in between, for a tidy solution:
Everything is hidden behind these macros:
#ifdef __cplusplus
#define static_forward(decl) namespace { extern decl; }
#define static_def(def) namespace { def; }
#else
#define static_forward(decl) static decl;
#define static_def(def) static def;
#endif
And so we can do:
static_forward(struct foo foo_instance)
void some_function(void)
{
do_something_with(&foo_instance);
}
static_def(struct foo foo_instance = { 1, 2, 3 })
The C expansion is straightforward, looking like this:
static struct foo foo_instance;
void some_function(void)
{
do_something_with(&foo_instance);
}
static struct foo foo_instance = { 1, 2, 3 };
The C++ expansion looks like this:
namespace { extern struct foo foo_instance; }
void some_function(void)
{
do_something_with(&foo_instance);
}
namespace { struct foo foo_instance = { 1, 2, 3 }; }
So, in a nutshell, thanks to anonymous namespaces, C++ does not actually have a static forward reference problem, only the problem of implementing it in a C incompatible way, which is bridgeable with macros.
Multiple anonymous namespace regions in the same translation unit are the same namespace, and the surrounding file scope outside of the namespace has visibility into it.

Related

Redefining a handle ptr of void* to handle ptr to struct* (C/C++ mixcode) for access

I have C/C++ mix code and want to pass around a struct that contains a reference to a class. Because of this, I can't declare this struct in the header file of the C++ component (because class is defined in source file of C++ component) but only in the source file. The main script in C however has to reference that struct somehow, so I typedef it to void*. However because of that, I can't dereference the handle type back to a struct. Redefining the handle pointer in the source file is not possible. How can I work around this?
header_with_obj.hpp
class A {
int a;
};
header.hpp
typedef void* config_handle_t;
source.cpp
#include "header.hpp"
#include "header_with_obj.hpp"
typedef struct {
A* ptr;
int some_other;
} config_t;
// typedef config_t* config_handle_t <-- error: conflicting declaration 'typedef struct config_t* config_handle_t '
int foo(void* arg)
{
config_handle_t handle = (config_handle_t) arg;
handle->A.a = 4; // <-- error: 'config_handle_t' {aka 'void*'} is not a pointer-to-object type
}
main.c
#include "header.hpp"
int main()
{
// we get that void* from somewhere and pass it in
foo(arg);
}
The usual way to do this is to use an undefined struct. In its most basic form:
void foo(struct the_config_struct *arg);
// OK even though 'struct the_config_struct' wasn't defined!
// surprisingly this is also allowed in C++
You can also make a typedef:
typedef struct the_config_struct *config_handle_t;
void foo(config_handle_t arg);
and if you want, you can even call the typedef the same thing as the struct. Just to avoid confusing people, I wouldn't do this unless it's a typedef for the struct (not a pointer).
typedef struct the_config_struct the_config_struct;
void foo(the_config_struct *arg);
You don't to actually have defined the struct until you want to access its members:
// if we uncomment this definition then it's OK
// struct my_struct {
// char *message;
// };
void foo(struct my_struct *arg) {
puts(arg->message); // error: struct my_struct is undefined
}
Finally (since this confused you before) you should know that typedef names and struct names are completely separate in C.
struct foo {}; // defines "struct foo" but "foo" is completely unrelated
typedef int bar; // defines "bar" but "struct bar" is completely unrelated
foo *get_foo(); // error: "foo" is unknown
struct foo *get_foo(); // OK
typedef struct bar foo;
foo *get_bar(); // OK: returns pointer to struct bar (not struct foo!)
struct foo *get_foo(); // this one returns pointer to struct foo
struct baz {};
typedef struct baz baz;
// now "baz" is an alternative name for "struct baz" - they are interchangeable
typedef struct baz {} baz; // short version
and structs don't have to have names:
// foo is a variable, and it's a struct variable, but the struct has no name.
// so we have no way to use the struct for anything else.
struct {
int i;
} foo;
// The struct is still there even though it doesn't have a name!
// In C++ you can write decltype(bar) to say "the same type as variable bar".
// Even though we don't know the person's name we can still yell out "Hey you in the red shirt!"
decltype(foo) foo2; // a variable foo2. The type is decltype(foo) i.e. the struct from before
// GCC lets you do it in C using "typeof".
// This is not standard. It's a special feature in GCC.
typeof(foo) foo2;
// This struct also has no name either. But the typedef means we have
// an "unofficial" way to name it, just like decltype(foo) before.
// This is valid in C as well as C++.
typedef struct {
char message[50];
} bar;

Typedef function vs function pointer

I'm trying to understand function declaration using typedefs.
What does this code do in C++?
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
fcn_t *pf;
ptr_t pf2;
In my understanding:
fcn_t is the type of a function, and so the line with f is a function declaration (not a definition), and I could later define it like void f(void) { blabla(); bleble(); } just as if I had declared void f(void); instead of fcn_t f;;
fcn_t * is the type of a function pointer, and the line with pf is a pointer variable definition, and pf is default-initialized (assuming the code excerpt is from the global scope);
There is no difference between fcn_t* and ptr_t, thus everything I said about pf applies to pf2.
Did I get it right? Would any of the three declarations have its meaning changed if I marked them extern? What would change if the code was compiled as C instead of as C++?
Yes you are right on all three counts. The only thing that would change if you marked them extern are the function pointers. Function declarations are by default extern in C++.
Try and compile the following program
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
// constexpr auto one = WhichType<fcn_t>{};
// constexpr auto two = WhichType<fcn_t*>{};
// constexpr auto three = WhichType<ptr_t>{};
fcn_t f;
void f() {}
int main() {
f();
}
Uncommenting the commented lines will likely give you a compiler error that tells you what types the WhichType instance is being instantiated with, and as a result it should show you the exact types of all three things you asked about. It's a trick I picked up from Scott Meyers' book "Effective Modern C++".
To test whether the declarations are extern or not, write two simple implementation files, with one containing the definition of the variable
main.cpp
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
int main() {
f();
}
definition.cpp
void f() {}
and then compile, link and run definition.cpp and main.cpp (via g++ -std=c++14 definition.cpp main.cpp and then ./a.out). If the declaration was not extern then the compile would fail with an undefined symbol error.
Here is a simple illustration of these typedef
#include <stdio.h>
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
fcn_t *pf;
ptr_t pf2;
void
f(void)
{
printf("I am void\n");
}
void
vSayHi(void)
{
printf( "Hi\n" );
}
int
main(void)
{
pf2 = vSayHi;
pf2();
pf = vSayHi;
pf();
f();
return 0;
}
OUTPUT:
Hi
Hi
I am void

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;

Initializing const value in c++ header with value returned by function

Is there any way to define conastant foo in c++ header "foo.hpp"
const int foo;
and initialize it with value returned by function bar defined in "bar.hpp"
int bar();
? (Either in foo.hpp or in foo.cpp.)
Write
extern const int foo;
in foo.hpp and
const int foo = bar();
in foo.cpp.
Of course there is:
// foo.hpp
const int foo = bar();
as you can see here it works just fine.

Elegantly reuse code adding const to a class instantiation

I need to compile the same code with two different libraries. One allows the objects to be const, the other doesn't. The solution that's implemented now looks like this:
#ifdef (OLDLIB)
ClassFoo TheFoo = Bar();
#else
const ClassFoo TheFoo = Bar();
#endif
This is used many times for different classes and impedes readability. I'd like to make the distinction somewhere else.
I guess one could say:
#ifdef (OLDLIB)
#define CLASS_FOO ClassFoo
#define CLASS_BAR ClassBar
#else
#define CLASS_FOO const ClassFoo
#define CLASS_BAR const ClassBar
#endif
CLASS_FOO TheFoo = Bar();
CLASS_BAR TheBar = FooBar();
But I dislike preprocessor stuff. Is there a nice C++-Way of doing the above? Thanks.
Update 1:
As Peter Wood said, it is possible to just instantiate them non-const. I changed the sentence.
You can use std::conditional to select between two types based on a compile-time variable:
#ifdef OLDLIB
constexpr bool OLD = true;
#else
constexpr bool OLD = false;
#endif
std::conditional<OLD, ClassFoo, const ClassFoo>::type theFoo;
~~~ ~~~~~~~~ ~~~~~~~~~~~~~~
true false
Since C++11
I'm pretty sure you're stuck with the preprocessor to accomplish your goal.
However, I'd probably write it like this:
#ifdef OLDLIB
# define LIB_CONST
#else
# define LIB_CONST const
LIB_CONST ClassFoo TheFoo(Bar());
Either way is not super elegant but doing it this way at least means that you're only tweaking an object attribute via the preprocessor rather than the whole object declaration.
The easiest solution seems to be to just use non-const objects and let the compiler automatically add const where the new interface expects it.
Alternately could you use a typedef inside the proprocessor block?
#ifdef (OLDLIB)
typedef ClassFoo InstantiableFoo;
#else
typedef const ClassFoo InstantiableFoo;
#endif
You can typedef
// oldlib.h
typedef ClassFoo Foo;
typedef ClassBar Bar;
// newlib.h
typedef const ClassFoo Foo;
typedef const ClassBar Bar;
// the library's user
#include "oldlib.h" // or include "which_lib.h" that includes
// one of oldlib.h newlib.h
#include "your_library_that_uses_the_typedefs.h"
Foo TheFoo = Bar();
Bar TheBar = FooBar();
You can parametrize your library's classes and global functions
// library.h
template <class Foo>
class SomeClass { }
template <class Foo>
Foo makeFoo() { }
// library_user.cpp
#include "library.h"
SomeClass<const ClassFoo> sc;
sc.method();
const ClassFoo f = makeFoo();
You can even hide the type Foo inside of the external libraries
// external_library.h
class ExternalLibrary {
typedef const Foo foo_type;
};
ExternalLibrary::foo_type& foo_identity(const ExternalLibrary::foo_type &v) { return v; }
// your_library.h
ExternalLibrary::foo_type makeFoo() { }
foo_identity(f1);