]>
Commit | Line | Data |
---|---|---|
20effc67 | 1 | // Copyright (c) 2009-2020 Vladimir Batov. |
7c673cae FG |
2 | // Use, modification and distribution are subject to the Boost Software License, |
3 | // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. | |
4 | ||
5 | #ifndef BOOST_CONVERT_HAS_MEMBER_HPP | |
6 | #define BOOST_CONVERT_HAS_MEMBER_HPP | |
7 | ||
7c673cae FG |
8 | #include <boost/type_traits/detail/yes_no_type.hpp> |
9 | ||
10 | // This macro allows to check if a type has a member named "__member_name__"... | |
11 | // ... regardless of the signature. If takes advantage of the following behavior related to | |
12 | // function resolution. Say, both, foo and base, declare a method with the same name "func": | |
13 | // | |
14 | // struct foo { int func (int, int) { return 0; } }; | |
15 | // struct base { void func () {} }; | |
16 | // struct mixin : public foo, public base {}; | |
17 | // | |
18 | // Now, if we inherit from both -- foo and base -- classes, then the following calls will fail | |
19 | // mixin_ptr(0)->func(); | |
20 | // mixin_ptr(0)->func(5, 5); | |
21 | // with the error message (gcc): request for member func is ambiguous | |
22 | // regardless if we provide any arguments or not even though one might expect that | |
23 | // arg-based signature resolution might kick in. The only way to deploy those methods is: | |
24 | // | |
25 | // mixin_ptr(0)->foo::func(); | |
26 | // mixin_ptr(0)->base::func(5, 5); | |
27 | // | |
28 | // C2. The actual signature of __member_name__ is not taken into account. If | |
29 | // __T__::__member_name__(any-signature) exists, then the introduced base::__member_name__ | |
30 | // will cause mixin->__member_name__() call to fail to compile (due to ambiguity). | |
31 | // C3. &U::__member_name__ (a.k.a. &mixin::__member_name__) | |
32 | // has the type of func_type only if __T__::__member_name__ does not exist. | |
33 | // If __T__::member_name does exist, then mixin::__member_name__ is ambiguous | |
34 | // and "yes_type test (...)" kicks in instead. | |
35 | // C4. Need to find some unique/ugly name so that it does not clash if this macro is | |
36 | // used inside some other template class; | |
37 | ||
38 | #define BOOST_DECLARE_HAS_MEMBER(__trait_name__, __member_name__) \ | |
39 | \ | |
40 | template <typename __boost_has_member_T__> /*C4*/ \ | |
41 | class __trait_name__ \ | |
42 | { \ | |
20effc67 TL |
43 | using check_type = typename boost::remove_const<__boost_has_member_T__>::type; \ |
44 | using yes_type = ::boost::type_traits::yes_type; \ | |
45 | using no_type = ::boost::type_traits:: no_type; \ | |
7c673cae FG |
46 | \ |
47 | struct base { void __member_name__(/*C2*/) {}}; \ | |
48 | struct mixin : public base, public check_type {}; \ | |
49 | \ | |
50 | template <void (base::*)()> struct aux {}; \ | |
51 | \ | |
52 | template <typename U> static no_type test(aux<&U::__member_name__>*); /*C3*/ \ | |
53 | template <typename U> static yes_type test(...); \ | |
54 | \ | |
55 | public: \ | |
56 | \ | |
57 | BOOST_STATIC_CONSTANT(bool, value = (sizeof(yes_type) == sizeof(test<mixin>(0)))); \ | |
58 | } | |
59 | ||
60 | #endif // BOOST_CONVERT_HAS_MEMBER_HPP |