Detect if a type exists in C++ [duplicate]
Asked Answered
D

2

8

I'd need a template which can be called like this:

int x = type_exists< std::vector<int> >::value;

This should set x to 1 if #include <vector> was present (either explicitly or transitively) earlier in the source, otherwise it should set x to 0.

Is it possible to do it in C++? I'm using GCC, so GCC extensions are also fine.

It's also OK to change the call syntax a bit.

It's not OK to run the C++ compiler twice: first just to figure out if we get a compile error.

Drivein answered 15/12, 2013 at 11:3 Comment(17)
What would you do with such a function?Interpretive
Related: How to detect existence of a class using SFINAE?Wryneck
@gx_: I couldn't find anything useful there. class_defined would require adding CLASS_DEFINED_CHECK to the vector header, and has_destructor is a compile error for undefined classes.Drivein
@Mat: Once that's available, I'd like provide a fallback implementation for classes which are not defined in the library header.Drivein
In general, you can only use names in C++ which have been declared. There is no general "reflection" or "bare word" support in the language that would allow you to, say, examine the state of the parser. It's a little different for class template members, but that's special.Vulgarian
@pts: what if someone includes vector after your header? I'm really not seeing your use-case.Interpretive
@Mat: Let's suppose some libraries' vector headers define the supervector template as well. My header includes vector, and I'd like to use the system's supervector<int> if available, otherwise, I'd like to use my fallback implementation.Drivein
@Drivein As clearly explained for has_destructor, you need to declare the name to test, then it works: coliru.stacked-crooked.com/a/4b39006dfae715d0 . A potential problem, as shown in the second part of the main, is that if you declare a defined class you must do it at the same scope (and namespace) of the definition.Wryneck
@gx_: How does has_destructor work for a template like vector<int>? How do I pre-declare that?Drivein
If it's Visual C++ you use __if_exists. If not, well, sorry...Lifelong
@Drivein Can you explain why you don't want to use the standard implementation of vector and why you don't want to check for the symbol _VECTOR_ ?Fritzsche
@Drivein Indeed vector is a problem. If you forward-declare namespace std { template<class T, class Alloc> class vector; } you can't use “std::vector<int>” (missing 2nd template argument) if <vector> wasn't included, but if you try namespace std { template<class T> class allocator; template<class T, class Alloc = allocator<T> > class vector; } then you will get an error (redefinition of default template argument) if <vector> was included or later is. Sorry I can't find a solution at the moment. (Note that I linked the other question as “related”, not “duplicate”)Wryneck
I'm curious. What would the use case be?Precocious
@Fritzsche The C++ Standard doesn't say that the header <vector> defines _VECTOR_. With GCC 4.8.1 it doesn't; it defines _GLIBCXX_VECTOR as an include guard (but I wouldn't rely on that).Wryneck
@Wryneck Not only that, but forward declaring a class from the standard is (in most cases) undefined behaviour.Napkin
@Napkin I wasn't sure about forward declarations (as opposed to adding definitions or new declarations), but indeed (I wasn't comfortable with that anyway...). Thanks for the reminder :)Wryneck
@Wryneck The link in the link says section 17.4.3.1/3: "If the program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this clause, the behavior is undefined." So I guess that's the end of it. This link also says ...I can't think of any way that this extension could break a conforming program, considering that users are not permitted to forward-declare standard library components...Moan
T
9

This is not what you are looking for, but it's as close as you can get to a type_exists trait:

template<class T> struct Void { typedef void type; };

template<class T, class U = void>
struct type_exists { enum { value = 0 }; };

template<class T>
struct type_exists<T, typename Void<T>::type> { enum { value = 1 }; };

Apparently, it works:

static_assert(type_exists<int>::value, "int is not defined");
static_assert(type_exists<SomeNonexistingType>::value, "expected compile-time error");

This does exactly what it is supposed to do. Tested with GCC 5.4.0.

Ternopol answered 1/12, 2016 at 8:31 Comment(2)
Indeed, with this definition of type_exists, int x = type_exists< std::vector<int> >::value; doesn't compile if <vector> is not included, so this doesn't solve my problem.Drivein
static_assert(!type_exists<SomeNonexistingType>::value, "SomeNonexistingType should not exist"); should succeed, but fails to compile.Eba
P
4

This is not possible, I'm afraid. If we were to use a non defined identifier we would get a compilation error, leading to this code:

int x = type_exists< std::vector<int> >::value;

not to even compile.

Also, the standard doesn't specify any preprocessor directive to be declared within the header file (which is implementation defined instead) for the standard library, therefore you won't be able to detect it even with preprocessor macros.

Precocious answered 15/12, 2013 at 12:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.