1

I'm playing around with SFINAE, but I'm trying to get some meaningful compiler-error information while dealing with macro-generated code. I used THIS answer to get the following running: (I want to check with member_test(a) whether Type A has some previously defined members)

//Check for member variable with given name.
#define CREATE_MEMBER_VAR_CHECK(var_name)                                   \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct has_member_var_##var_name : std::false_type {};                      \
                                                                            \
template<typename T>                                                        \
struct has_member_var_##var_name<                                           \
    T                                                                       \
    , std::integral_constant<                                               \
        bool, std::is_member_object_pointer<decltype(&T::var_name)>::value  \
    >                                                                       \
> : std::true_type {};

#define MEMB_CHECK_WRAPPER(r, data,  elem) CREATE_MEMBER_VAR_CHECK(elem)


#define CREATE_ENABLE_IF_CLAUSE(var_name)                       \
  class = typename std::enable_if<has_member_var_##var_name<T>::value>::type

#define ENABLE_IF_CLAUSE_WRAPPER(r, data, i, elem)               \
            BOOST_PP_COMMA_IF(i) CREATE_ENABLE_IF_CLAUSE(elem)


#define TO_MEMBER_TEST(member_seq)                                               \
            BOOST_PP_SEQ_FOR_EACH(MEMB_CHECK_WRAPPER, _, member_seq)             \
                                                                                 \
            template < typename T,                                               \
                BOOST_PP_SEQ_FOR_EACH_I(ENABLE_IF_CLAUSE_WRAPPER, _, member_seq) \
            >                                                                    \
            void member_test(const T & )                                         \
            {                                                                    \
                std::cout << "works!!\n\n";                                      \
            }

When I then do the following, then everything will be fine:

TO_MEMBER_TEST((x)(y)(z))

struct A { int x, y, z; };


int main(int argc, char const *argv[])
{
    A a;
    member_test(a);
}

However, when I use TO_MEMBER_TEST((x)(y)(z)(dummy)) instead, then the code won't compile (as intended), because member_test(A&) is not defined anymore, because A.dummy doesn't exists. The compiler will give me something like: template argument deduction/substitution failed: error: no type named 'type' in 'struct std::enable_if'

How can I say something like 'There is no member dummy.' instead (e.g. with static_asserts)?

Community
  • 1
  • 1
  • Sorry, I had to update the title.. And I found [THIS](http://stackoverflow.com/a/264088/2081073)... looks almost right... – user2081073 Mar 03 '13 at 15:57

1 Answers1

0

Hmm, actually enable_if is not necessary when I really want a specific compiler-error with static_assert, so I came up with this solution:

//Check for member variable with given name.
#define CREATE_MEMBER_VAR_CHECK(var_name)                                   \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct has_member_var_##var_name : std::false_type {};                      \
                                                                            \
template<typename T>                                                        \
struct has_member_var_##var_name<                                           \
    T                                                                       \
    , std::integral_constant<                                               \
        bool, std::is_member_object_pointer<decltype(&T::var_name)>::value  \
    >                                                                       \
> : std::true_type {};

#define MEMB_CHECK_WRAPPER(r, data,  elem) CREATE_MEMBER_VAR_CHECK(elem)


#define MEMBER_ERROR(type_name, var_name) \
    #var_name is not a member of #type_name

#define CHECK_HAS_MEMBER(type_name, var_name)                                   \
        static_assert(has_member_var_##var_name<type_name>::value,              \
                      BOOST_PP_STRINGIZE(MEMBER_ERROR(type_name, var_name)) );

#define CHECK_HAS_MEMBER_WRAPPER(r, data, elem) CHECK_HAS_MEMBER(data, elem)

#define TO_MEMBER_TEST(type, member_seq)                                        \
            BOOST_PP_SEQ_FOR_EACH(MEMB_CHECK_WRAPPER, _, member_seq)            \
            BOOST_PP_SEQ_FOR_EACH(CHECK_HAS_MEMBER_WRAPPER, type, member_seq)   \
                                                                                \
            template < typename type>                                           \
            void member_test(const type & )                                     \
            {                                                                   \
                std::cout << "works!!\n\n";                                     \
            }                                                                   



struct A { int x, y, z; };

TO_MEMBER_TEST(A,(x)(y)(z)(dummy))

Adding the call CHECK_HAS_MEMBER() to the end of the macro CREATE_MEMBER_VAR_CHECK makes this even more 'readable'.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055