Let's say I have a struct Foo
and I want to determine if Foo
has an int
inside of it.
struct Foo { int a; char c; };
has_int<Foo>::value; // should be true
This is the most basic form of what I'd actually want, checking for a specific type:
has_type<Foo, int>::value;
If I knew how to do the above I could transform it to what my end goal is:
has_pointer<Foo>::value; // false
struct Bar { int a; void *b; };
has_pointer<Bar>::value; // true
As for what I've tried, it's hard to get started, the best I can think of is that if I could get a pack of the types contained in a struct, I could write the rest:
template <typename... Ts>
constexpr bool any_is_pointer() noexcept {
return (... || std::is_pointer_v<Ts>);
}
What I'm asking for seems like it may very well be impossible. I couldn't find a duplicate, but I was surprised that I couldn't so it might be out there.
As others have said, what you want is impossible right now with vanilla C++ for arbitrary types. But if you are able to provide certain compile-time information alongside the types you need to operate on in their definition, you can do what you are trying to do.
You can do this with the boost fusion library's adapters, which allow you to adapt existing structures to become fusion containers or define new structures which model a fusion container. You can then use any boost::mpl algorithms you want to do the types of compile-time checks you want to do.
Consider this example, using your struct foo
, and your desired has_type
compile time algorithm:
#include <boost/fusion/adapted/struct/define_struct.hpp>
#include <boost/mpl/contains.hpp>
BOOST_FUSION_DEFINE_STRUCT(
(your_namespace), foo,
(int, a)
(char, c))
template<typename source_type, typename search_type>
struct has_type
{
typedef typename boost::mpl::contains<source_type, search_type>::type value_type;
static const bool value = value_type::value;
};
#include <iostream>
int main()
{
bool foo_has_int_pointer = has_type<your_namespace::foo, int*>::value;
bool foo_has_int = has_type<your_namespace::foo, int>::value;
std::cout << "foo_has_int_pointer: " << foo_has_int_pointer << "\n";
std::cout << "foo_has_int: " << foo_has_int << "\n";
your_namespace::foo my_foo;
my_foo.a = 10;
my_foo.c = 'x';
std::cout << "my_foo: " << my_foo.a << ", " << my_foo.c;
}
View the output or mess with the example here: http://ideone.com/f0Zc2M
As you can see, you use the BOOST_FUSION_DEFINE_STRUCT macro to define the struct
whose members you'd like to operate on at compile-time. fusion provides several other macros for defining structures like this, as well as macros for adapting already defined structures. Check them out here.
Of course, you probably can already tell the down-side here. has_type
will only work if source_type
is a boost::mpl / boost::fusion sequence. For you, this means that any type you want to reason about at compile time in this way, you need to define or adapt using the macros. This may not be acceptable to you if you're writing a library that is intended to work for arbitrary library-user-defined types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With