I wanted to detect if I have a member in a simple POD struct and after some searching and merging some methods I found on the web I've come up with this solution:
#include <iostream>
template<class...Fs>
struct funcs_t{};
template<class F0, class...Fs>
struct funcs_t<F0, Fs...>: F0, funcs_t<Fs...> {
funcs_t(F0 f0, Fs... fs):
F0(std::move(f0)), funcs_t<Fs...>(std::move(fs)...)
{}
using F0::operator();
using funcs_t<Fs...>::operator();
};
template<class F>
struct funcs_t<F>:F {
funcs_t(F f) : F(std::move(f)) {};
using F::operator();
};
template<class...Fs>
funcs_t<std::decay_t<Fs>...> funcs(Fs&&...fs) {
return {std::forward<Fs>(fs)...};
}
#define HAS_MEMBER(cls, memb)\
[](){\
auto with_memb = [](auto &&A, int x)\
-> decltype(typename std::remove_reference<decltype(A)>::type().memb, std::true_type())\
{\
return std::true_type();\
};\
auto with_no_memb = [](auto &&A, float x) -> std::false_type {\
return std::false_type();\
};\
auto has_memb = funcs(with_memb, with_no_memb);\
return has_memb(cls(), 1);\
}()
struct A {
int a;
int b;
};
int main(int argc, char const *argv[])
{
std::cout << HAS_MEMBER(A, b) << std::endl;
return 0;
}
-
1\$\begingroup\$ Why do you need this? What are you trying to achieve? \$\endgroup\$Loki Astari– Loki Astari2019年07月19日 16:39:58 +00:00Commented Jul 19, 2019 at 16:39
-
\$\begingroup\$ I have different pod structs with many common fields with the same meaning and I wanted to print them on screen. I will see if I can use it for other things but for now that's what I needed it for. \$\endgroup\$Pangi– Pangi2019年07月19日 18:45:41 +00:00Commented Jul 19, 2019 at 18:45
-
\$\begingroup\$ Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers . If you want a fixed-version of your code to be available, post it as answer linking to Deduplicator's for credit (or post it as a new question, but it's hardly a major change). \$\endgroup\$Mast– Mast ♦2019年07月19日 19:04:47 +00:00Commented Jul 19, 2019 at 19:04
-
\$\begingroup\$ Ok, I'll keep that in mind. \$\endgroup\$Pangi– Pangi2019年07月19日 19:16:34 +00:00Commented Jul 19, 2019 at 19:16
1 Answer 1
Your detector fails in the face of overloading and templating. Also, it will only detect (static) member-variables and (static) member-functions. While you can extend it to types (and type-aliases), accepting templates and overloading would need better language-provided reflection-facilities.
Anyway, pure existence is generally uninteresting, supported operations count.
funcs()
andfuncs_t
are nearly a generally useful abstraction.Just use perfect forwarding instead of by-value and
std::move()
. Allowing for all callables, includingfinal
classes, function-pointers, member-function-pointers, and the same wrapped in astd::reference_wrapper
would admittedly add significant amounts of code.A good name would be
overloaded
.HAS_MEMBER
needlessly depends on default-constructing the passed class. Fix that by usingdecltype
,std::declval()
and unevaluated contexts.If you don't use an argument, don't name it. Specifically for
main()
, just don't ask for it.Don't use
std::endl
. In the rare cases you actually need to flush manually, be explicit and usestd::flush
. Nearly always you are just crippling performance.return 0;
is implicit formain()
. Make of that what you will.