How to check if a class is declared in C++?










14















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.










share|improve this question
























  • 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















14















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.










share|improve this question
























  • 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













14












14








14








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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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

















  • 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












6 Answers
6






active

oldest

votes


















11














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.






share|improve this answer

























  • 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





    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 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



















12














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.






share|improve this answer

























  • 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



















3














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.






share|improve this answer























  • 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











  • 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











  • @nm_tp: See ideone.com/UuyHr4

    – Bathsheba
    Nov 14 '18 at 13:15


















3














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).






share|improve this answer

























  • 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











  • @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



















2














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

...






share|improve this answer























  • 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


















2














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.






share|improve this answer

























  • 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











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
);



);













draft saved

draft discarded


















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









11














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.






share|improve this answer

























  • 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





    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 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
















11














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.






share|improve this answer

























  • 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





    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 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














11












11








11







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 15 '18 at 11:35

























answered Nov 14 '18 at 10:34









StoryTellerStoryTeller

101k12206274




101k12206274












  • 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





    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 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


















  • 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





    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 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

















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














12














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.






share|improve this answer

























  • 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
















12














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.






share|improve this answer

























  • 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














12












12








12







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








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


















  • 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












3














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.






share|improve this answer























  • 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











  • 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











  • @nm_tp: See ideone.com/UuyHr4

    – Bathsheba
    Nov 14 '18 at 13:15















3














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.






share|improve this answer























  • 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











  • 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











  • @nm_tp: See ideone.com/UuyHr4

    – Bathsheba
    Nov 14 '18 at 13:15













3












3








3







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.






share|improve this answer













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.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 14 '18 at 10:37









BathshebaBathsheba

180k27254383




180k27254383












  • 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











  • 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











  • @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











  • 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 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
















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











3














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).






share|improve this answer

























  • 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











  • @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
















3














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).






share|improve this answer

























  • 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











  • @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














3












3








3







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).






share|improve this answer















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).







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 14 '18 at 11:50

























answered Nov 14 '18 at 10:35









QuentinQuentin

46.4k589146




46.4k589146












  • 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











  • @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











  • 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












2














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

...






share|improve this answer























  • 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















2














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

...






share|improve this answer























  • 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













2












2








2







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

...






share|improve this answer













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

...







share|improve this answer












share|improve this answer



share|improve this answer










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

















  • 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











2














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.






share|improve this answer

























  • 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
















2














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.






share|improve this answer

























  • 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














2












2








2







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








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


















  • 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


















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Use pre created SQLite database for Android project in kotlin

Darth Vader #20

Ondo