I have a class that varies according to a compilation flag. I would like to instantiate both the versions of the class in the same scope.
my_class.h
#ifndef MY_CLASS_H
#define MY_CLASS_H
#ifdef COMP_FLAG
#define MY_CLASS MyClassFlagged
#else
#define MY_CLASS MyClassNotFlagged
#endif
class MY_CLASS
{
};
#endif
Then, I have created two header files:
my_class_flagged.h
and my_class_not_flagged.h
my_class_flagged.h
#ifndef MY_CLASS_FLAGGED
#define MY_CLASS_FLAGGED
#include "my_class.h"
#endif
my_class_not_flagged.h
#ifndef MY_CLASS_NOT_FLAGGED
#define MY_CLASS_NOT_FLAGGED
#include "my_class.h"
#endif
I am using bazel as build system, so I have compiled them with COMP_FLAG
and without it to create two separate targets.
BUILD
cc_library(
name = "not_flagged",
hdrs = ["my_class.h"],
)
cc_library(
name = "flagged",
hdrs = ["my_class.h"],
defines = ["COMP_FLAG"],
)
cc_library(
name = "my_class_flagged",
hdrs = ["my_class_flagged.h"],
deps = [":flagged"],
)
cc_library(
name = "my_class_not_flagged",
hdrs = ["my_class_not_flagged.h"],
deps = [":not_flagged"],
)
Then I am not able to instantiate both of them but only one:
#include "my_class_flagged.h"
#include "my_class_not_flagged.h"
// NOT BUILD
TEST(MyClassNotFlaggedTest, NotFlaggedInstantiation)
{
MyClassNotFlagged my_class_not_flagged;
std::ignore = my_class_not_flagged;
}
// PASS
TEST(MyClassFlaggedTest, FlaggedInstantiation)
{
MyClassFlagged my_class_flagged;
std::ignore = my_class_flagged;
}
obtaining this error:
error: 'MyClassNotFlagged' was not declared in this scope; did you mean 'MyClassFlagged'?
where I have used:
cc_test(
name = "test",
srcs = ["test.cpp"],
deps = [
":my_class_flagged",
":my_class_not_flagged",
],
)
I have tried to modify my_class.h
file:
#ifdef COMP_FLAG
#ifndef MY_CLASS_FLAGGED_H
#define MY_CLASS_FLAGGED_H
#define MY_CLASS MyClassFlagged
class MY_CLASS
{
};
#endif // MY_CLASS_FLAGGED_H
#else
#ifndef MY_CLASS_NOT_FLAGGED_H
#define MY_CLASS_NOT_FLAGGED_H
#define MY_CLASS MyClassNotFlagged
class MY_CLASS
{
};
#endif // MY_CLASS_NOT_FLAGGED_H
#endif
However, now I got both test not building:
error: 'MyClassNotFlagged' was not declared in this scope
error: 'MyClassFlagged' was not declared in this scope
.
I am afraid this isn't the answer, because from comments it is already apparent that your example is too much simplified. Anyhow, it appears you make something very simple into something complicated. Use the language when you can, only resort to conditional compilation using the preprocessor when needed. Nothing in your example really needs the preprocessor.
You can define one class template:
template <int tag>
struct MY_CLASS {};
using MyClassFlagged = MY_CLASS<0>;
using MyClassNotFlagged = MY_CLASS<1>;
There are ways to determine the difference between this approach and defining two separate (non-template) classes, but for most uses and applications that difference should not matter.
If you want to stay with the preprocessor (for whatever reasons) then I suggest to at least leave the build system out. Include the header twice, define and undefine the flag explicitly in your code.
In the my_class_flagged.h
write:
#ifndef MY_CLASS_FLAGGED
#define MY_CLASS_FLAGGED
#define COMP_FLAG
#include "my_class.h"
#undef COMP_FLAG
#endif
And in my_class_not_flagged.h
write:
#ifndef MY_CLASS_NOT_FLAGGED
#define MY_CLASS_NOT_FLAGGED
#include "my_class.h"
#endif
And remove the include guards from my_class.h
. And I suggest to rename it to eg my_class.x
or whatever you like different from .h
to indicate it shall not be included directly.
And, in my_class.h
as the last line before closing the header guard, add:
#undef MY_CLASS
If you do that, you can include both headers (in any order) in main.cpp
to have both classes defined.