How to check if a class is declared in C++?
I am writing a piece of software around a framework and a class I am using (to be precise, extending) was renamed in a later version. Is there some way to write some macros/templates in C++11 in order to determine if a class with a certain name had been declared at the point in code?
An illustration of what I'm trying to accomplish follows.
Let's say that file class_include.h contains either the definition of class A
:
class A
...
;
or class B
:
class B
...
;
and class C
tries to extend whichever of those is declared:
#include <class_include.h>
#if (class A is declared)
class C : public A
#else // class B is declared
class C : public B
#endif
...
;
Note: It came to my mind to try and check a version of the framework but the answer to this question interests me. I also cannot change any framework header files.
EDIT: The accepted answer depends on whether the class is defined (which implies declaration) and, in my case, the class is declared iff it's defined.
c++ c++11
|
show 1 more comment
I am writing a piece of software around a framework and a class I am using (to be precise, extending) was renamed in a later version. Is there some way to write some macros/templates in C++11 in order to determine if a class with a certain name had been declared at the point in code?
An illustration of what I'm trying to accomplish follows.
Let's say that file class_include.h contains either the definition of class A
:
class A
...
;
or class B
:
class B
...
;
and class C
tries to extend whichever of those is declared:
#include <class_include.h>
#if (class A is declared)
class C : public A
#else // class B is declared
class C : public B
#endif
...
;
Note: It came to my mind to try and check a version of the framework but the answer to this question interests me. I also cannot change any framework header files.
EDIT: The accepted answer depends on whether the class is defined (which implies declaration) and, in my case, the class is declared iff it's defined.
c++ c++11
And when both A and B are declared (not saying it'll impact the answer; but you should certainly know what you want to happen)
– UKMonkey
Nov 14 '18 at 10:24
They will not be declared at the same time. As I said, A was at one point renamed into B. That being said, a compile error would be preferable in this hypothetical situation.
– nm_tp
Nov 14 '18 at 10:30
As an aside, this was a really poor decision on the part of the library maintainer, unless they ran both side by side for a few versions and you ignored a deprecation warning? ;)
– Lightness Races in Orbit
Nov 14 '18 at 11:35
No warnings, just code working with an older version and me trying to upgrade to the new version. Then, this issue popped up. Admittedly, I still lack detailed knowledge of the library.
– nm_tp
Nov 14 '18 at 11:40
Why don't include corresponding class header according to the version number?
– serge
Nov 14 '18 at 12:20
|
show 1 more comment
I am writing a piece of software around a framework and a class I am using (to be precise, extending) was renamed in a later version. Is there some way to write some macros/templates in C++11 in order to determine if a class with a certain name had been declared at the point in code?
An illustration of what I'm trying to accomplish follows.
Let's say that file class_include.h contains either the definition of class A
:
class A
...
;
or class B
:
class B
...
;
and class C
tries to extend whichever of those is declared:
#include <class_include.h>
#if (class A is declared)
class C : public A
#else // class B is declared
class C : public B
#endif
...
;
Note: It came to my mind to try and check a version of the framework but the answer to this question interests me. I also cannot change any framework header files.
EDIT: The accepted answer depends on whether the class is defined (which implies declaration) and, in my case, the class is declared iff it's defined.
c++ c++11
I am writing a piece of software around a framework and a class I am using (to be precise, extending) was renamed in a later version. Is there some way to write some macros/templates in C++11 in order to determine if a class with a certain name had been declared at the point in code?
An illustration of what I'm trying to accomplish follows.
Let's say that file class_include.h contains either the definition of class A
:
class A
...
;
or class B
:
class B
...
;
and class C
tries to extend whichever of those is declared:
#include <class_include.h>
#if (class A is declared)
class C : public A
#else // class B is declared
class C : public B
#endif
...
;
Note: It came to my mind to try and check a version of the framework but the answer to this question interests me. I also cannot change any framework header files.
EDIT: The accepted answer depends on whether the class is defined (which implies declaration) and, in my case, the class is declared iff it's defined.
c++ c++11
c++ c++11
edited Nov 19 '18 at 11:09
nm_tp
asked Nov 14 '18 at 10:17
nm_tpnm_tp
16310
16310
And when both A and B are declared (not saying it'll impact the answer; but you should certainly know what you want to happen)
– UKMonkey
Nov 14 '18 at 10:24
They will not be declared at the same time. As I said, A was at one point renamed into B. That being said, a compile error would be preferable in this hypothetical situation.
– nm_tp
Nov 14 '18 at 10:30
As an aside, this was a really poor decision on the part of the library maintainer, unless they ran both side by side for a few versions and you ignored a deprecation warning? ;)
– Lightness Races in Orbit
Nov 14 '18 at 11:35
No warnings, just code working with an older version and me trying to upgrade to the new version. Then, this issue popped up. Admittedly, I still lack detailed knowledge of the library.
– nm_tp
Nov 14 '18 at 11:40
Why don't include corresponding class header according to the version number?
– serge
Nov 14 '18 at 12:20
|
show 1 more comment
And when both A and B are declared (not saying it'll impact the answer; but you should certainly know what you want to happen)
– UKMonkey
Nov 14 '18 at 10:24
They will not be declared at the same time. As I said, A was at one point renamed into B. That being said, a compile error would be preferable in this hypothetical situation.
– nm_tp
Nov 14 '18 at 10:30
As an aside, this was a really poor decision on the part of the library maintainer, unless they ran both side by side for a few versions and you ignored a deprecation warning? ;)
– Lightness Races in Orbit
Nov 14 '18 at 11:35
No warnings, just code working with an older version and me trying to upgrade to the new version. Then, this issue popped up. Admittedly, I still lack detailed knowledge of the library.
– nm_tp
Nov 14 '18 at 11:40
Why don't include corresponding class header according to the version number?
– serge
Nov 14 '18 at 12:20
And when both A and B are declared (not saying it'll impact the answer; but you should certainly know what you want to happen)
– UKMonkey
Nov 14 '18 at 10:24
And when both A and B are declared (not saying it'll impact the answer; but you should certainly know what you want to happen)
– UKMonkey
Nov 14 '18 at 10:24
They will not be declared at the same time. As I said, A was at one point renamed into B. That being said, a compile error would be preferable in this hypothetical situation.
– nm_tp
Nov 14 '18 at 10:30
They will not be declared at the same time. As I said, A was at one point renamed into B. That being said, a compile error would be preferable in this hypothetical situation.
– nm_tp
Nov 14 '18 at 10:30
As an aside, this was a really poor decision on the part of the library maintainer, unless they ran both side by side for a few versions and you ignored a deprecation warning? ;)
– Lightness Races in Orbit
Nov 14 '18 at 11:35
As an aside, this was a really poor decision on the part of the library maintainer, unless they ran both side by side for a few versions and you ignored a deprecation warning? ;)
– Lightness Races in Orbit
Nov 14 '18 at 11:35
No warnings, just code working with an older version and me trying to upgrade to the new version. Then, this issue popped up. Admittedly, I still lack detailed knowledge of the library.
– nm_tp
Nov 14 '18 at 11:40
No warnings, just code working with an older version and me trying to upgrade to the new version. Then, this issue popped up. Admittedly, I still lack detailed knowledge of the library.
– nm_tp
Nov 14 '18 at 11:40
Why don't include corresponding class header according to the version number?
– serge
Nov 14 '18 at 12:20
Why don't include corresponding class header according to the version number?
– serge
Nov 14 '18 at 12:20
|
show 1 more comment
6 Answers
6
active
oldest
votes
You can, and with no macros required. First an observation, you can "forward" declare a class even after its full definition is available. I.e. this is valid:
class foo;
class foo;
Now, with the help of a homebrew void_t
implementation and an is_complete
type utility, you can do something like this:
#include <type_traits>
template<typename... Ts> struct make_void typedef void type;;
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T, typename Enabler = void>
struct is_complete : std::false_type ;
template <typename T>
struct is_complete<T, ::void_t<decltype(sizeof(T) != 0)>> : std::true_type ;
class A;
class B;
class C : public std::conditional<is_complete<A>::value, A, B>::type
;
Depending on whether or not the full definition of A
is present, C
will inherit from A
or B
publicly. See a live example.
But I caution, this needs to be handled with care or you are very likely to have an ODR-violation in your program.
Note thatis_complete
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:37
2
Now look at this, you beat me by a whole minute with the same idea. I must be rusty ;)
– Quentin
Nov 14 '18 at 10:38
@Jarod42 - Nothing ventured nothing gained. Maybe in C++20 we can do this with less danger? Fingers crossed anyway.
– StoryTeller
Nov 14 '18 at 10:39
How does this work if bothA
andB
are abstract?
– nm_tp
Nov 15 '18 at 7:56
@nm_tp - Should work just the same.sizeof
isn't barred from being applied to abstract classes, and it simply cannot evaluate to0
for any object type. The "abstract" only means logical abstraction.
– StoryTeller
Nov 15 '18 at 8:01
|
show 1 more comment
In addition to the template magic ideas already given, the traditional approach is to use the library's "version" macros if possible. If there aren't any, can't you just change your code and start using the new version of the library? Denote the new version of the dependency in your build system as appropriate.
Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
The other answers do technically achieve your goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
This is definitely something I would do, too, but the client might not want to be able to use various versions. I shall definitely try to use the version macros. +1
– nm_tp
Nov 14 '18 at 10:57
@nm_tp Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
– Lightness Races in Orbit
Nov 14 '18 at 11:02
This is actually the only right answer here. The other answers check if the class is defined not if the class is declared as written in the question!
– Oliv
Nov 14 '18 at 11:14
@Oliv: While the wording in the question is imprecise, the intent/goal is clear. The other answers do technically achieve that goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
– Lightness Races in Orbit
Nov 14 '18 at 11:21
1
@Oliv: I consider every overblown template metagubbins given here to be a hack. One author even claims it "simplifies things quite a bit"!! Checking for a header guard is a hack but a better one. Checking for a version macro is perfect but probably unnecessary (though I have done this before with Boost when the sink API changed and caused me different behaviour at runtime; ugh)
– Lightness Races in Orbit
Nov 14 '18 at 11:31
|
show 7 more comments
One way is to exploit SFINAE using typeid
which will have a different result from an incomplete type:
#include <iostream>
#include <typeinfo> // for typeid
template<typename T, typename = void>
constexpr bool is_defined = false;
template<typename T>
constexpr bool is_defined<T, decltype(typeid(T), void())> = true;
struct complete ; // i.e. `complete` is defined.
struct incomplete; // not defined, just a forward declaration
int main()
std::cout << is_defined<complete> << " " << is_defined<incomplete>;
This requires you to forward declare the classes though, but as is_defined
is constexpr
it can be used at compile time. You could use sizeof
too but I'm nervous about empty base class optimisations yielding false positives.
Note thatis_defined
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:41
Fear not,sizeof
anything will always be at least 1. Taking EBO into account in such a context would be maddeningly complex anyway.
– Quentin
Nov 14 '18 at 10:41
The question is "when the class is declared".
– Oliv
Nov 14 '18 at 11:11
This causes several compiler errors. Which compiler and compile flags are you using? I tried withg++ -std=c++11 filename.cpp
– nm_tp
Nov 14 '18 at 12:54
@nm_tp: See ideone.com/UuyHr4
– Bathsheba
Nov 14 '18 at 13:15
add a comment |
In your case, since you want to inherit from the class, it has to be declared but also defined; and this simplifies things quite a bit.
namespace detail_detectDefinedClass
template <class Void, class First, class... Rest>
struct detect : detect<Void, Rest...> ;
template <class First, class... Rest>
struct detect<std::void_t<decltype(sizeof(First))>, First, Rest...>
using type = First;
;
template <class... Classes>
using DetectDefinedClass = typename detail_detectDefinedClass::detect<
std::void_t<>, Classes...
>::type;
struct A /* B */
;
class C : public DetectDefinedClass<struct A, struct B>
;
static_assert(std::is_base_of_v<A, C>);
//static_assert(std::is_base_of_v<B, C>);
This uses SFINAE by trying to use sizeof
on the requested type, which only works if the type has been defined (struct A
in the template's argument list merely declares it).
Note thatDetectDefinedClass
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:42
So the question when it is declared, and your code cause the declaration of the two classes.
– Oliv
Nov 14 '18 at 11:12
@Oliv As I wrote in my answer, this checks whether the classes are defined, not merely declared.
– Quentin
Nov 14 '18 at 11:49
@YSC no reason, it remained from a previous iteration but is indeed useless now.
– Quentin
Nov 14 '18 at 11:49
As stated in the link that follows, the void_t has been available since C++17. Or am I missing something? en.cppreference.com/w/cpp/types/void_t
– nm_tp
Nov 14 '18 at 13:10
|
show 2 more comments
You may use a type alias and select the right one according to the library version
#ifdef LIB_VER_123
typedef A A1;
#else
typedef B A1;
#endif
class C : public A1
...
I think that it's clear from my question that I can't do that. This would be a perfect solution but I can't obtain the version.
– nm_tp
Nov 14 '18 at 13:08
You may introduce the version yourself when compiling with a different versions. I.e. as a compiler/preprocessor option-D LIB_VER_123
– serge
Nov 14 '18 at 14:29
Yes! How could I've forgot this! Thanks!
– nm_tp
Nov 14 '18 at 14:45
@nm_tp you are welcome!
– serge
Nov 14 '18 at 14:52
add a comment |
You could use the class code guard:
//classA.h
#ifndef cgA
#define cgA
class A ;
#endif
//classB.h
#ifndef cgB
#define cgB
class B ;
#endif
//classC.h
#include classA.h
#include classB.h
#ifdef cgA
class C : public A
#else
class C : public B
#endif
Edit with extra comment info: You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
Quoting myself: "I also cannot change any framework include files."
– nm_tp
Nov 14 '18 at 10:32
What does that mean? You cannot change classA.h or classB.h? You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
– Frederik De Ruyck
Nov 14 '18 at 10:50
That doesn't really follow Frederik unless I'm misunderstanding you. However the idea to check whether the header guard of the desired header is defined is actually a good one, as long as it changed along with the name of the class within it.
– Lightness Races in Orbit
Nov 14 '18 at 11:26
This is the first thing that came to my mind but is just not feasible in my situation, as I have stated.
– nm_tp
Nov 14 '18 at 11:34
@nm_tp Why not? It doesn't require changing any framework include files. Unless the headers are weird, the guards are there, already, ready-made and ready to go.
– Lightness Races in Orbit
Nov 14 '18 at 11:39
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53297795%2fhow-to-check-if-a-class-is-declared-in-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can, and with no macros required. First an observation, you can "forward" declare a class even after its full definition is available. I.e. this is valid:
class foo;
class foo;
Now, with the help of a homebrew void_t
implementation and an is_complete
type utility, you can do something like this:
#include <type_traits>
template<typename... Ts> struct make_void typedef void type;;
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T, typename Enabler = void>
struct is_complete : std::false_type ;
template <typename T>
struct is_complete<T, ::void_t<decltype(sizeof(T) != 0)>> : std::true_type ;
class A;
class B;
class C : public std::conditional<is_complete<A>::value, A, B>::type
;
Depending on whether or not the full definition of A
is present, C
will inherit from A
or B
publicly. See a live example.
But I caution, this needs to be handled with care or you are very likely to have an ODR-violation in your program.
Note thatis_complete
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:37
2
Now look at this, you beat me by a whole minute with the same idea. I must be rusty ;)
– Quentin
Nov 14 '18 at 10:38
@Jarod42 - Nothing ventured nothing gained. Maybe in C++20 we can do this with less danger? Fingers crossed anyway.
– StoryTeller
Nov 14 '18 at 10:39
How does this work if bothA
andB
are abstract?
– nm_tp
Nov 15 '18 at 7:56
@nm_tp - Should work just the same.sizeof
isn't barred from being applied to abstract classes, and it simply cannot evaluate to0
for any object type. The "abstract" only means logical abstraction.
– StoryTeller
Nov 15 '18 at 8:01
|
show 1 more comment
You can, and with no macros required. First an observation, you can "forward" declare a class even after its full definition is available. I.e. this is valid:
class foo;
class foo;
Now, with the help of a homebrew void_t
implementation and an is_complete
type utility, you can do something like this:
#include <type_traits>
template<typename... Ts> struct make_void typedef void type;;
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T, typename Enabler = void>
struct is_complete : std::false_type ;
template <typename T>
struct is_complete<T, ::void_t<decltype(sizeof(T) != 0)>> : std::true_type ;
class A;
class B;
class C : public std::conditional<is_complete<A>::value, A, B>::type
;
Depending on whether or not the full definition of A
is present, C
will inherit from A
or B
publicly. See a live example.
But I caution, this needs to be handled with care or you are very likely to have an ODR-violation in your program.
Note thatis_complete
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:37
2
Now look at this, you beat me by a whole minute with the same idea. I must be rusty ;)
– Quentin
Nov 14 '18 at 10:38
@Jarod42 - Nothing ventured nothing gained. Maybe in C++20 we can do this with less danger? Fingers crossed anyway.
– StoryTeller
Nov 14 '18 at 10:39
How does this work if bothA
andB
are abstract?
– nm_tp
Nov 15 '18 at 7:56
@nm_tp - Should work just the same.sizeof
isn't barred from being applied to abstract classes, and it simply cannot evaluate to0
for any object type. The "abstract" only means logical abstraction.
– StoryTeller
Nov 15 '18 at 8:01
|
show 1 more comment
You can, and with no macros required. First an observation, you can "forward" declare a class even after its full definition is available. I.e. this is valid:
class foo;
class foo;
Now, with the help of a homebrew void_t
implementation and an is_complete
type utility, you can do something like this:
#include <type_traits>
template<typename... Ts> struct make_void typedef void type;;
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T, typename Enabler = void>
struct is_complete : std::false_type ;
template <typename T>
struct is_complete<T, ::void_t<decltype(sizeof(T) != 0)>> : std::true_type ;
class A;
class B;
class C : public std::conditional<is_complete<A>::value, A, B>::type
;
Depending on whether or not the full definition of A
is present, C
will inherit from A
or B
publicly. See a live example.
But I caution, this needs to be handled with care or you are very likely to have an ODR-violation in your program.
You can, and with no macros required. First an observation, you can "forward" declare a class even after its full definition is available. I.e. this is valid:
class foo;
class foo;
Now, with the help of a homebrew void_t
implementation and an is_complete
type utility, you can do something like this:
#include <type_traits>
template<typename... Ts> struct make_void typedef void type;;
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T, typename Enabler = void>
struct is_complete : std::false_type ;
template <typename T>
struct is_complete<T, ::void_t<decltype(sizeof(T) != 0)>> : std::true_type ;
class A;
class B;
class C : public std::conditional<is_complete<A>::value, A, B>::type
;
Depending on whether or not the full definition of A
is present, C
will inherit from A
or B
publicly. See a live example.
But I caution, this needs to be handled with care or you are very likely to have an ODR-violation in your program.
edited Nov 15 '18 at 11:35
answered Nov 14 '18 at 10:34
StoryTellerStoryTeller
101k12206274
101k12206274
Note thatis_complete
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:37
2
Now look at this, you beat me by a whole minute with the same idea. I must be rusty ;)
– Quentin
Nov 14 '18 at 10:38
@Jarod42 - Nothing ventured nothing gained. Maybe in C++20 we can do this with less danger? Fingers crossed anyway.
– StoryTeller
Nov 14 '18 at 10:39
How does this work if bothA
andB
are abstract?
– nm_tp
Nov 15 '18 at 7:56
@nm_tp - Should work just the same.sizeof
isn't barred from being applied to abstract classes, and it simply cannot evaluate to0
for any object type. The "abstract" only means logical abstraction.
– StoryTeller
Nov 15 '18 at 8:01
|
show 1 more comment
Note thatis_complete
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:37
2
Now look at this, you beat me by a whole minute with the same idea. I must be rusty ;)
– Quentin
Nov 14 '18 at 10:38
@Jarod42 - Nothing ventured nothing gained. Maybe in C++20 we can do this with less danger? Fingers crossed anyway.
– StoryTeller
Nov 14 '18 at 10:39
How does this work if bothA
andB
are abstract?
– nm_tp
Nov 15 '18 at 7:56
@nm_tp - Should work just the same.sizeof
isn't barred from being applied to abstract classes, and it simply cannot evaluate to0
for any object type. The "abstract" only means logical abstraction.
– StoryTeller
Nov 15 '18 at 8:01
Note that
is_complete
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.– Jarod42
Nov 14 '18 at 10:37
Note that
is_complete
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.– Jarod42
Nov 14 '18 at 10:37
2
2
Now look at this, you beat me by a whole minute with the same idea. I must be rusty ;)
– Quentin
Nov 14 '18 at 10:38
Now look at this, you beat me by a whole minute with the same idea. I must be rusty ;)
– Quentin
Nov 14 '18 at 10:38
@Jarod42 - Nothing ventured nothing gained. Maybe in C++20 we can do this with less danger? Fingers crossed anyway.
– StoryTeller
Nov 14 '18 at 10:39
@Jarod42 - Nothing ventured nothing gained. Maybe in C++20 we can do this with less danger? Fingers crossed anyway.
– StoryTeller
Nov 14 '18 at 10:39
How does this work if both
A
and B
are abstract?– nm_tp
Nov 15 '18 at 7:56
How does this work if both
A
and B
are abstract?– nm_tp
Nov 15 '18 at 7:56
@nm_tp - Should work just the same.
sizeof
isn't barred from being applied to abstract classes, and it simply cannot evaluate to 0
for any object type. The "abstract" only means logical abstraction.– StoryTeller
Nov 15 '18 at 8:01
@nm_tp - Should work just the same.
sizeof
isn't barred from being applied to abstract classes, and it simply cannot evaluate to 0
for any object type. The "abstract" only means logical abstraction.– StoryTeller
Nov 15 '18 at 8:01
|
show 1 more comment
In addition to the template magic ideas already given, the traditional approach is to use the library's "version" macros if possible. If there aren't any, can't you just change your code and start using the new version of the library? Denote the new version of the dependency in your build system as appropriate.
Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
The other answers do technically achieve your goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
This is definitely something I would do, too, but the client might not want to be able to use various versions. I shall definitely try to use the version macros. +1
– nm_tp
Nov 14 '18 at 10:57
@nm_tp Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
– Lightness Races in Orbit
Nov 14 '18 at 11:02
This is actually the only right answer here. The other answers check if the class is defined not if the class is declared as written in the question!
– Oliv
Nov 14 '18 at 11:14
@Oliv: While the wording in the question is imprecise, the intent/goal is clear. The other answers do technically achieve that goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
– Lightness Races in Orbit
Nov 14 '18 at 11:21
1
@Oliv: I consider every overblown template metagubbins given here to be a hack. One author even claims it "simplifies things quite a bit"!! Checking for a header guard is a hack but a better one. Checking for a version macro is perfect but probably unnecessary (though I have done this before with Boost when the sink API changed and caused me different behaviour at runtime; ugh)
– Lightness Races in Orbit
Nov 14 '18 at 11:31
|
show 7 more comments
In addition to the template magic ideas already given, the traditional approach is to use the library's "version" macros if possible. If there aren't any, can't you just change your code and start using the new version of the library? Denote the new version of the dependency in your build system as appropriate.
Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
The other answers do technically achieve your goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
This is definitely something I would do, too, but the client might not want to be able to use various versions. I shall definitely try to use the version macros. +1
– nm_tp
Nov 14 '18 at 10:57
@nm_tp Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
– Lightness Races in Orbit
Nov 14 '18 at 11:02
This is actually the only right answer here. The other answers check if the class is defined not if the class is declared as written in the question!
– Oliv
Nov 14 '18 at 11:14
@Oliv: While the wording in the question is imprecise, the intent/goal is clear. The other answers do technically achieve that goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
– Lightness Races in Orbit
Nov 14 '18 at 11:21
1
@Oliv: I consider every overblown template metagubbins given here to be a hack. One author even claims it "simplifies things quite a bit"!! Checking for a header guard is a hack but a better one. Checking for a version macro is perfect but probably unnecessary (though I have done this before with Boost when the sink API changed and caused me different behaviour at runtime; ugh)
– Lightness Races in Orbit
Nov 14 '18 at 11:31
|
show 7 more comments
In addition to the template magic ideas already given, the traditional approach is to use the library's "version" macros if possible. If there aren't any, can't you just change your code and start using the new version of the library? Denote the new version of the dependency in your build system as appropriate.
Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
The other answers do technically achieve your goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
In addition to the template magic ideas already given, the traditional approach is to use the library's "version" macros if possible. If there aren't any, can't you just change your code and start using the new version of the library? Denote the new version of the dependency in your build system as appropriate.
Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
The other answers do technically achieve your goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
edited Nov 14 '18 at 11:23
answered Nov 14 '18 at 10:38
Lightness Races in OrbitLightness Races in Orbit
292k53475807
292k53475807
This is definitely something I would do, too, but the client might not want to be able to use various versions. I shall definitely try to use the version macros. +1
– nm_tp
Nov 14 '18 at 10:57
@nm_tp Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
– Lightness Races in Orbit
Nov 14 '18 at 11:02
This is actually the only right answer here. The other answers check if the class is defined not if the class is declared as written in the question!
– Oliv
Nov 14 '18 at 11:14
@Oliv: While the wording in the question is imprecise, the intent/goal is clear. The other answers do technically achieve that goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
– Lightness Races in Orbit
Nov 14 '18 at 11:21
1
@Oliv: I consider every overblown template metagubbins given here to be a hack. One author even claims it "simplifies things quite a bit"!! Checking for a header guard is a hack but a better one. Checking for a version macro is perfect but probably unnecessary (though I have done this before with Boost when the sink API changed and caused me different behaviour at runtime; ugh)
– Lightness Races in Orbit
Nov 14 '18 at 11:31
|
show 7 more comments
This is definitely something I would do, too, but the client might not want to be able to use various versions. I shall definitely try to use the version macros. +1
– nm_tp
Nov 14 '18 at 10:57
@nm_tp Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
– Lightness Races in Orbit
Nov 14 '18 at 11:02
This is actually the only right answer here. The other answers check if the class is defined not if the class is declared as written in the question!
– Oliv
Nov 14 '18 at 11:14
@Oliv: While the wording in the question is imprecise, the intent/goal is clear. The other answers do technically achieve that goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
– Lightness Races in Orbit
Nov 14 '18 at 11:21
1
@Oliv: I consider every overblown template metagubbins given here to be a hack. One author even claims it "simplifies things quite a bit"!! Checking for a header guard is a hack but a better one. Checking for a version macro is perfect but probably unnecessary (though I have done this before with Boost when the sink API changed and caused me different behaviour at runtime; ugh)
– Lightness Races in Orbit
Nov 14 '18 at 11:31
This is definitely something I would do, too, but the client might not want to be able to use various versions. I shall definitely try to use the version macros. +1
– nm_tp
Nov 14 '18 at 10:57
This is definitely something I would do, too, but the client might not want to be able to use various versions. I shall definitely try to use the version macros. +1
– nm_tp
Nov 14 '18 at 10:57
@nm_tp Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
– Lightness Races in Orbit
Nov 14 '18 at 11:02
@nm_tp Ultimately, dependency control is a normal and expected part of the software deployment process. So, even though it can be a bit of a pain in the arse, I wouldn't overcomplicate your code solely in attempt to completely eliminate it. I mean you already have to list the library in some form as a dependency so you're halfway there before you've even started!
– Lightness Races in Orbit
Nov 14 '18 at 11:02
This is actually the only right answer here. The other answers check if the class is defined not if the class is declared as written in the question!
– Oliv
Nov 14 '18 at 11:14
This is actually the only right answer here. The other answers check if the class is defined not if the class is declared as written in the question!
– Oliv
Nov 14 '18 at 11:14
@Oliv: While the wording in the question is imprecise, the intent/goal is clear. The other answers do technically achieve that goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
– Lightness Races in Orbit
Nov 14 '18 at 11:21
@Oliv: While the wording in the question is imprecise, the intent/goal is clear. The other answers do technically achieve that goal, as long as we assume that "class A is defined" can be considered equivalent to "class A is defined and takes the form of exactly what we think it should take the form of". Without working dependency control you are already kind of screwed, and with it you do not need hacks.
– Lightness Races in Orbit
Nov 14 '18 at 11:21
1
1
@Oliv: I consider every overblown template metagubbins given here to be a hack. One author even claims it "simplifies things quite a bit"!! Checking for a header guard is a hack but a better one. Checking for a version macro is perfect but probably unnecessary (though I have done this before with Boost when the sink API changed and caused me different behaviour at runtime; ugh)
– Lightness Races in Orbit
Nov 14 '18 at 11:31
@Oliv: I consider every overblown template metagubbins given here to be a hack. One author even claims it "simplifies things quite a bit"!! Checking for a header guard is a hack but a better one. Checking for a version macro is perfect but probably unnecessary (though I have done this before with Boost when the sink API changed and caused me different behaviour at runtime; ugh)
– Lightness Races in Orbit
Nov 14 '18 at 11:31
|
show 7 more comments
One way is to exploit SFINAE using typeid
which will have a different result from an incomplete type:
#include <iostream>
#include <typeinfo> // for typeid
template<typename T, typename = void>
constexpr bool is_defined = false;
template<typename T>
constexpr bool is_defined<T, decltype(typeid(T), void())> = true;
struct complete ; // i.e. `complete` is defined.
struct incomplete; // not defined, just a forward declaration
int main()
std::cout << is_defined<complete> << " " << is_defined<incomplete>;
This requires you to forward declare the classes though, but as is_defined
is constexpr
it can be used at compile time. You could use sizeof
too but I'm nervous about empty base class optimisations yielding false positives.
Note thatis_defined
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:41
Fear not,sizeof
anything will always be at least 1. Taking EBO into account in such a context would be maddeningly complex anyway.
– Quentin
Nov 14 '18 at 10:41
The question is "when the class is declared".
– Oliv
Nov 14 '18 at 11:11
This causes several compiler errors. Which compiler and compile flags are you using? I tried withg++ -std=c++11 filename.cpp
– nm_tp
Nov 14 '18 at 12:54
@nm_tp: See ideone.com/UuyHr4
– Bathsheba
Nov 14 '18 at 13:15
add a comment |
One way is to exploit SFINAE using typeid
which will have a different result from an incomplete type:
#include <iostream>
#include <typeinfo> // for typeid
template<typename T, typename = void>
constexpr bool is_defined = false;
template<typename T>
constexpr bool is_defined<T, decltype(typeid(T), void())> = true;
struct complete ; // i.e. `complete` is defined.
struct incomplete; // not defined, just a forward declaration
int main()
std::cout << is_defined<complete> << " " << is_defined<incomplete>;
This requires you to forward declare the classes though, but as is_defined
is constexpr
it can be used at compile time. You could use sizeof
too but I'm nervous about empty base class optimisations yielding false positives.
Note thatis_defined
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:41
Fear not,sizeof
anything will always be at least 1. Taking EBO into account in such a context would be maddeningly complex anyway.
– Quentin
Nov 14 '18 at 10:41
The question is "when the class is declared".
– Oliv
Nov 14 '18 at 11:11
This causes several compiler errors. Which compiler and compile flags are you using? I tried withg++ -std=c++11 filename.cpp
– nm_tp
Nov 14 '18 at 12:54
@nm_tp: See ideone.com/UuyHr4
– Bathsheba
Nov 14 '18 at 13:15
add a comment |
One way is to exploit SFINAE using typeid
which will have a different result from an incomplete type:
#include <iostream>
#include <typeinfo> // for typeid
template<typename T, typename = void>
constexpr bool is_defined = false;
template<typename T>
constexpr bool is_defined<T, decltype(typeid(T), void())> = true;
struct complete ; // i.e. `complete` is defined.
struct incomplete; // not defined, just a forward declaration
int main()
std::cout << is_defined<complete> << " " << is_defined<incomplete>;
This requires you to forward declare the classes though, but as is_defined
is constexpr
it can be used at compile time. You could use sizeof
too but I'm nervous about empty base class optimisations yielding false positives.
One way is to exploit SFINAE using typeid
which will have a different result from an incomplete type:
#include <iostream>
#include <typeinfo> // for typeid
template<typename T, typename = void>
constexpr bool is_defined = false;
template<typename T>
constexpr bool is_defined<T, decltype(typeid(T), void())> = true;
struct complete ; // i.e. `complete` is defined.
struct incomplete; // not defined, just a forward declaration
int main()
std::cout << is_defined<complete> << " " << is_defined<incomplete>;
This requires you to forward declare the classes though, but as is_defined
is constexpr
it can be used at compile time. You could use sizeof
too but I'm nervous about empty base class optimisations yielding false positives.
answered Nov 14 '18 at 10:37
BathshebaBathsheba
180k27254383
180k27254383
Note thatis_defined
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:41
Fear not,sizeof
anything will always be at least 1. Taking EBO into account in such a context would be maddeningly complex anyway.
– Quentin
Nov 14 '18 at 10:41
The question is "when the class is declared".
– Oliv
Nov 14 '18 at 11:11
This causes several compiler errors. Which compiler and compile flags are you using? I tried withg++ -std=c++11 filename.cpp
– nm_tp
Nov 14 '18 at 12:54
@nm_tp: See ideone.com/UuyHr4
– Bathsheba
Nov 14 '18 at 13:15
add a comment |
Note thatis_defined
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:41
Fear not,sizeof
anything will always be at least 1. Taking EBO into account in such a context would be maddeningly complex anyway.
– Quentin
Nov 14 '18 at 10:41
The question is "when the class is declared".
– Oliv
Nov 14 '18 at 11:11
This causes several compiler errors. Which compiler and compile flags are you using? I tried withg++ -std=c++11 filename.cpp
– nm_tp
Nov 14 '18 at 12:54
@nm_tp: See ideone.com/UuyHr4
– Bathsheba
Nov 14 '18 at 13:15
Note that
is_defined
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.– Jarod42
Nov 14 '18 at 10:41
Note that
is_defined
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.– Jarod42
Nov 14 '18 at 10:41
Fear not,
sizeof
anything will always be at least 1. Taking EBO into account in such a context would be maddeningly complex anyway.– Quentin
Nov 14 '18 at 10:41
Fear not,
sizeof
anything will always be at least 1. Taking EBO into account in such a context would be maddeningly complex anyway.– Quentin
Nov 14 '18 at 10:41
The question is "when the class is declared".
– Oliv
Nov 14 '18 at 11:11
The question is "when the class is declared".
– Oliv
Nov 14 '18 at 11:11
This causes several compiler errors. Which compiler and compile flags are you using? I tried with
g++ -std=c++11 filename.cpp
– nm_tp
Nov 14 '18 at 12:54
This causes several compiler errors. Which compiler and compile flags are you using? I tried with
g++ -std=c++11 filename.cpp
– nm_tp
Nov 14 '18 at 12:54
@nm_tp: See ideone.com/UuyHr4
– Bathsheba
Nov 14 '18 at 13:15
@nm_tp: See ideone.com/UuyHr4
– Bathsheba
Nov 14 '18 at 13:15
add a comment |
In your case, since you want to inherit from the class, it has to be declared but also defined; and this simplifies things quite a bit.
namespace detail_detectDefinedClass
template <class Void, class First, class... Rest>
struct detect : detect<Void, Rest...> ;
template <class First, class... Rest>
struct detect<std::void_t<decltype(sizeof(First))>, First, Rest...>
using type = First;
;
template <class... Classes>
using DetectDefinedClass = typename detail_detectDefinedClass::detect<
std::void_t<>, Classes...
>::type;
struct A /* B */
;
class C : public DetectDefinedClass<struct A, struct B>
;
static_assert(std::is_base_of_v<A, C>);
//static_assert(std::is_base_of_v<B, C>);
This uses SFINAE by trying to use sizeof
on the requested type, which only works if the type has been defined (struct A
in the template's argument list merely declares it).
Note thatDetectDefinedClass
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:42
So the question when it is declared, and your code cause the declaration of the two classes.
– Oliv
Nov 14 '18 at 11:12
@Oliv As I wrote in my answer, this checks whether the classes are defined, not merely declared.
– Quentin
Nov 14 '18 at 11:49
@YSC no reason, it remained from a previous iteration but is indeed useless now.
– Quentin
Nov 14 '18 at 11:49
As stated in the link that follows, the void_t has been available since C++17. Or am I missing something? en.cppreference.com/w/cpp/types/void_t
– nm_tp
Nov 14 '18 at 13:10
|
show 2 more comments
In your case, since you want to inherit from the class, it has to be declared but also defined; and this simplifies things quite a bit.
namespace detail_detectDefinedClass
template <class Void, class First, class... Rest>
struct detect : detect<Void, Rest...> ;
template <class First, class... Rest>
struct detect<std::void_t<decltype(sizeof(First))>, First, Rest...>
using type = First;
;
template <class... Classes>
using DetectDefinedClass = typename detail_detectDefinedClass::detect<
std::void_t<>, Classes...
>::type;
struct A /* B */
;
class C : public DetectDefinedClass<struct A, struct B>
;
static_assert(std::is_base_of_v<A, C>);
//static_assert(std::is_base_of_v<B, C>);
This uses SFINAE by trying to use sizeof
on the requested type, which only works if the type has been defined (struct A
in the template's argument list merely declares it).
Note thatDetectDefinedClass
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:42
So the question when it is declared, and your code cause the declaration of the two classes.
– Oliv
Nov 14 '18 at 11:12
@Oliv As I wrote in my answer, this checks whether the classes are defined, not merely declared.
– Quentin
Nov 14 '18 at 11:49
@YSC no reason, it remained from a previous iteration but is indeed useless now.
– Quentin
Nov 14 '18 at 11:49
As stated in the link that follows, the void_t has been available since C++17. Or am I missing something? en.cppreference.com/w/cpp/types/void_t
– nm_tp
Nov 14 '18 at 13:10
|
show 2 more comments
In your case, since you want to inherit from the class, it has to be declared but also defined; and this simplifies things quite a bit.
namespace detail_detectDefinedClass
template <class Void, class First, class... Rest>
struct detect : detect<Void, Rest...> ;
template <class First, class... Rest>
struct detect<std::void_t<decltype(sizeof(First))>, First, Rest...>
using type = First;
;
template <class... Classes>
using DetectDefinedClass = typename detail_detectDefinedClass::detect<
std::void_t<>, Classes...
>::type;
struct A /* B */
;
class C : public DetectDefinedClass<struct A, struct B>
;
static_assert(std::is_base_of_v<A, C>);
//static_assert(std::is_base_of_v<B, C>);
This uses SFINAE by trying to use sizeof
on the requested type, which only works if the type has been defined (struct A
in the template's argument list merely declares it).
In your case, since you want to inherit from the class, it has to be declared but also defined; and this simplifies things quite a bit.
namespace detail_detectDefinedClass
template <class Void, class First, class... Rest>
struct detect : detect<Void, Rest...> ;
template <class First, class... Rest>
struct detect<std::void_t<decltype(sizeof(First))>, First, Rest...>
using type = First;
;
template <class... Classes>
using DetectDefinedClass = typename detail_detectDefinedClass::detect<
std::void_t<>, Classes...
>::type;
struct A /* B */
;
class C : public DetectDefinedClass<struct A, struct B>
;
static_assert(std::is_base_of_v<A, C>);
//static_assert(std::is_base_of_v<B, C>);
This uses SFINAE by trying to use sizeof
on the requested type, which only works if the type has been defined (struct A
in the template's argument list merely declares it).
edited Nov 14 '18 at 11:50
answered Nov 14 '18 at 10:35
QuentinQuentin
46.4k589146
46.4k589146
Note thatDetectDefinedClass
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:42
So the question when it is declared, and your code cause the declaration of the two classes.
– Oliv
Nov 14 '18 at 11:12
@Oliv As I wrote in my answer, this checks whether the classes are defined, not merely declared.
– Quentin
Nov 14 '18 at 11:49
@YSC no reason, it remained from a previous iteration but is indeed useless now.
– Quentin
Nov 14 '18 at 11:49
As stated in the link that follows, the void_t has been available since C++17. Or am I missing something? en.cppreference.com/w/cpp/types/void_t
– nm_tp
Nov 14 '18 at 13:10
|
show 2 more comments
Note thatDetectDefinedClass
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.
– Jarod42
Nov 14 '18 at 10:42
So the question when it is declared, and your code cause the declaration of the two classes.
– Oliv
Nov 14 '18 at 11:12
@Oliv As I wrote in my answer, this checks whether the classes are defined, not merely declared.
– Quentin
Nov 14 '18 at 11:49
@YSC no reason, it remained from a previous iteration but is indeed useless now.
– Quentin
Nov 14 '18 at 11:49
As stated in the link that follows, the void_t has been available since C++17. Or am I missing something? en.cppreference.com/w/cpp/types/void_t
– nm_tp
Nov 14 '18 at 13:10
Note that
DetectDefinedClass
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.– Jarod42
Nov 14 '18 at 10:42
Note that
DetectDefinedClass
is dangerous as it may produce ODR violation (Ill-formed program NDR :-( ) easily as it should be consistent across TUs.– Jarod42
Nov 14 '18 at 10:42
So the question when it is declared, and your code cause the declaration of the two classes.
– Oliv
Nov 14 '18 at 11:12
So the question when it is declared, and your code cause the declaration of the two classes.
– Oliv
Nov 14 '18 at 11:12
@Oliv As I wrote in my answer, this checks whether the classes are defined, not merely declared.
– Quentin
Nov 14 '18 at 11:49
@Oliv As I wrote in my answer, this checks whether the classes are defined, not merely declared.
– Quentin
Nov 14 '18 at 11:49
@YSC no reason, it remained from a previous iteration but is indeed useless now.
– Quentin
Nov 14 '18 at 11:49
@YSC no reason, it remained from a previous iteration but is indeed useless now.
– Quentin
Nov 14 '18 at 11:49
As stated in the link that follows, the void_t has been available since C++17. Or am I missing something? en.cppreference.com/w/cpp/types/void_t
– nm_tp
Nov 14 '18 at 13:10
As stated in the link that follows, the void_t has been available since C++17. Or am I missing something? en.cppreference.com/w/cpp/types/void_t
– nm_tp
Nov 14 '18 at 13:10
|
show 2 more comments
You may use a type alias and select the right one according to the library version
#ifdef LIB_VER_123
typedef A A1;
#else
typedef B A1;
#endif
class C : public A1
...
I think that it's clear from my question that I can't do that. This would be a perfect solution but I can't obtain the version.
– nm_tp
Nov 14 '18 at 13:08
You may introduce the version yourself when compiling with a different versions. I.e. as a compiler/preprocessor option-D LIB_VER_123
– serge
Nov 14 '18 at 14:29
Yes! How could I've forgot this! Thanks!
– nm_tp
Nov 14 '18 at 14:45
@nm_tp you are welcome!
– serge
Nov 14 '18 at 14:52
add a comment |
You may use a type alias and select the right one according to the library version
#ifdef LIB_VER_123
typedef A A1;
#else
typedef B A1;
#endif
class C : public A1
...
I think that it's clear from my question that I can't do that. This would be a perfect solution but I can't obtain the version.
– nm_tp
Nov 14 '18 at 13:08
You may introduce the version yourself when compiling with a different versions. I.e. as a compiler/preprocessor option-D LIB_VER_123
– serge
Nov 14 '18 at 14:29
Yes! How could I've forgot this! Thanks!
– nm_tp
Nov 14 '18 at 14:45
@nm_tp you are welcome!
– serge
Nov 14 '18 at 14:52
add a comment |
You may use a type alias and select the right one according to the library version
#ifdef LIB_VER_123
typedef A A1;
#else
typedef B A1;
#endif
class C : public A1
...
You may use a type alias and select the right one according to the library version
#ifdef LIB_VER_123
typedef A A1;
#else
typedef B A1;
#endif
class C : public A1
...
answered Nov 14 '18 at 13:06
sergeserge
70147
70147
I think that it's clear from my question that I can't do that. This would be a perfect solution but I can't obtain the version.
– nm_tp
Nov 14 '18 at 13:08
You may introduce the version yourself when compiling with a different versions. I.e. as a compiler/preprocessor option-D LIB_VER_123
– serge
Nov 14 '18 at 14:29
Yes! How could I've forgot this! Thanks!
– nm_tp
Nov 14 '18 at 14:45
@nm_tp you are welcome!
– serge
Nov 14 '18 at 14:52
add a comment |
I think that it's clear from my question that I can't do that. This would be a perfect solution but I can't obtain the version.
– nm_tp
Nov 14 '18 at 13:08
You may introduce the version yourself when compiling with a different versions. I.e. as a compiler/preprocessor option-D LIB_VER_123
– serge
Nov 14 '18 at 14:29
Yes! How could I've forgot this! Thanks!
– nm_tp
Nov 14 '18 at 14:45
@nm_tp you are welcome!
– serge
Nov 14 '18 at 14:52
I think that it's clear from my question that I can't do that. This would be a perfect solution but I can't obtain the version.
– nm_tp
Nov 14 '18 at 13:08
I think that it's clear from my question that I can't do that. This would be a perfect solution but I can't obtain the version.
– nm_tp
Nov 14 '18 at 13:08
You may introduce the version yourself when compiling with a different versions. I.e. as a compiler/preprocessor option
-D LIB_VER_123
– serge
Nov 14 '18 at 14:29
You may introduce the version yourself when compiling with a different versions. I.e. as a compiler/preprocessor option
-D LIB_VER_123
– serge
Nov 14 '18 at 14:29
Yes! How could I've forgot this! Thanks!
– nm_tp
Nov 14 '18 at 14:45
Yes! How could I've forgot this! Thanks!
– nm_tp
Nov 14 '18 at 14:45
@nm_tp you are welcome!
– serge
Nov 14 '18 at 14:52
@nm_tp you are welcome!
– serge
Nov 14 '18 at 14:52
add a comment |
You could use the class code guard:
//classA.h
#ifndef cgA
#define cgA
class A ;
#endif
//classB.h
#ifndef cgB
#define cgB
class B ;
#endif
//classC.h
#include classA.h
#include classB.h
#ifdef cgA
class C : public A
#else
class C : public B
#endif
Edit with extra comment info: You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
Quoting myself: "I also cannot change any framework include files."
– nm_tp
Nov 14 '18 at 10:32
What does that mean? You cannot change classA.h or classB.h? You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
– Frederik De Ruyck
Nov 14 '18 at 10:50
That doesn't really follow Frederik unless I'm misunderstanding you. However the idea to check whether the header guard of the desired header is defined is actually a good one, as long as it changed along with the name of the class within it.
– Lightness Races in Orbit
Nov 14 '18 at 11:26
This is the first thing that came to my mind but is just not feasible in my situation, as I have stated.
– nm_tp
Nov 14 '18 at 11:34
@nm_tp Why not? It doesn't require changing any framework include files. Unless the headers are weird, the guards are there, already, ready-made and ready to go.
– Lightness Races in Orbit
Nov 14 '18 at 11:39
|
show 1 more comment
You could use the class code guard:
//classA.h
#ifndef cgA
#define cgA
class A ;
#endif
//classB.h
#ifndef cgB
#define cgB
class B ;
#endif
//classC.h
#include classA.h
#include classB.h
#ifdef cgA
class C : public A
#else
class C : public B
#endif
Edit with extra comment info: You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
Quoting myself: "I also cannot change any framework include files."
– nm_tp
Nov 14 '18 at 10:32
What does that mean? You cannot change classA.h or classB.h? You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
– Frederik De Ruyck
Nov 14 '18 at 10:50
That doesn't really follow Frederik unless I'm misunderstanding you. However the idea to check whether the header guard of the desired header is defined is actually a good one, as long as it changed along with the name of the class within it.
– Lightness Races in Orbit
Nov 14 '18 at 11:26
This is the first thing that came to my mind but is just not feasible in my situation, as I have stated.
– nm_tp
Nov 14 '18 at 11:34
@nm_tp Why not? It doesn't require changing any framework include files. Unless the headers are weird, the guards are there, already, ready-made and ready to go.
– Lightness Races in Orbit
Nov 14 '18 at 11:39
|
show 1 more comment
You could use the class code guard:
//classA.h
#ifndef cgA
#define cgA
class A ;
#endif
//classB.h
#ifndef cgB
#define cgB
class B ;
#endif
//classC.h
#include classA.h
#include classB.h
#ifdef cgA
class C : public A
#else
class C : public B
#endif
Edit with extra comment info: You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
You could use the class code guard:
//classA.h
#ifndef cgA
#define cgA
class A ;
#endif
//classB.h
#ifndef cgB
#define cgB
class B ;
#endif
//classC.h
#include classA.h
#include classB.h
#ifdef cgA
class C : public A
#else
class C : public B
#endif
Edit with extra comment info: You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
edited Nov 30 '18 at 10:07
answered Nov 14 '18 at 10:30
Frederik De RuyckFrederik De Ruyck
28416
28416
Quoting myself: "I also cannot change any framework include files."
– nm_tp
Nov 14 '18 at 10:32
What does that mean? You cannot change classA.h or classB.h? You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
– Frederik De Ruyck
Nov 14 '18 at 10:50
That doesn't really follow Frederik unless I'm misunderstanding you. However the idea to check whether the header guard of the desired header is defined is actually a good one, as long as it changed along with the name of the class within it.
– Lightness Races in Orbit
Nov 14 '18 at 11:26
This is the first thing that came to my mind but is just not feasible in my situation, as I have stated.
– nm_tp
Nov 14 '18 at 11:34
@nm_tp Why not? It doesn't require changing any framework include files. Unless the headers are weird, the guards are there, already, ready-made and ready to go.
– Lightness Races in Orbit
Nov 14 '18 at 11:39
|
show 1 more comment
Quoting myself: "I also cannot change any framework include files."
– nm_tp
Nov 14 '18 at 10:32
What does that mean? You cannot change classA.h or classB.h? You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
– Frederik De Ruyck
Nov 14 '18 at 10:50
That doesn't really follow Frederik unless I'm misunderstanding you. However the idea to check whether the header guard of the desired header is defined is actually a good one, as long as it changed along with the name of the class within it.
– Lightness Races in Orbit
Nov 14 '18 at 11:26
This is the first thing that came to my mind but is just not feasible in my situation, as I have stated.
– nm_tp
Nov 14 '18 at 11:34
@nm_tp Why not? It doesn't require changing any framework include files. Unless the headers are weird, the guards are there, already, ready-made and ready to go.
– Lightness Races in Orbit
Nov 14 '18 at 11:39
Quoting myself: "I also cannot change any framework include files."
– nm_tp
Nov 14 '18 at 10:32
Quoting myself: "I also cannot change any framework include files."
– nm_tp
Nov 14 '18 at 10:32
What does that mean? You cannot change classA.h or classB.h? You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
– Frederik De Ruyck
Nov 14 '18 at 10:50
What does that mean? You cannot change classA.h or classB.h? You could add an empty classA.h and classB.h and refer to them as last in your includepath. If you framework does not contain A or B the empty files will be loaded.
– Frederik De Ruyck
Nov 14 '18 at 10:50
That doesn't really follow Frederik unless I'm misunderstanding you. However the idea to check whether the header guard of the desired header is defined is actually a good one, as long as it changed along with the name of the class within it.
– Lightness Races in Orbit
Nov 14 '18 at 11:26
That doesn't really follow Frederik unless I'm misunderstanding you. However the idea to check whether the header guard of the desired header is defined is actually a good one, as long as it changed along with the name of the class within it.
– Lightness Races in Orbit
Nov 14 '18 at 11:26
This is the first thing that came to my mind but is just not feasible in my situation, as I have stated.
– nm_tp
Nov 14 '18 at 11:34
This is the first thing that came to my mind but is just not feasible in my situation, as I have stated.
– nm_tp
Nov 14 '18 at 11:34
@nm_tp Why not? It doesn't require changing any framework include files. Unless the headers are weird, the guards are there, already, ready-made and ready to go.
– Lightness Races in Orbit
Nov 14 '18 at 11:39
@nm_tp Why not? It doesn't require changing any framework include files. Unless the headers are weird, the guards are there, already, ready-made and ready to go.
– Lightness Races in Orbit
Nov 14 '18 at 11:39
|
show 1 more comment
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53297795%2fhow-to-check-if-a-class-is-declared-in-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
And when both A and B are declared (not saying it'll impact the answer; but you should certainly know what you want to happen)
– UKMonkey
Nov 14 '18 at 10:24
They will not be declared at the same time. As I said, A was at one point renamed into B. That being said, a compile error would be preferable in this hypothetical situation.
– nm_tp
Nov 14 '18 at 10:30
As an aside, this was a really poor decision on the part of the library maintainer, unless they ran both side by side for a few versions and you ignored a deprecation warning? ;)
– Lightness Races in Orbit
Nov 14 '18 at 11:35
No warnings, just code working with an older version and me trying to upgrade to the new version. Then, this issue popped up. Admittedly, I still lack detailed knowledge of the library.
– nm_tp
Nov 14 '18 at 11:40
Why don't include corresponding class header according to the version number?
– serge
Nov 14 '18 at 12:20