Добавить сообщения об ошибках компиляции в макрос SFINAE

Я играю с SFINAE, но я пытаюсь получить значимую ошибку компилятора информация при работе с кодом, сгенерированным макросами. Я использовал ЭТОТ ответ, чтобы выполнить следующее: (Я хочу проверить с помощью member_test (a), есть ли у типа A ранее определенные члены)

//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";                                      \
            }

Когда я сделаю следующее, все будет хорошо:

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

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


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

Однако, когда я использую вместо этого TO_MEMBER_TEST((x)(y)(z)(dummy)), код не компилируется (как и предполагалось), потому что member_test (A &) больше не определен, потому что A.dummy не существует. Компилятор выдаст мне что-то вроде: ошибка вывода / подстановки аргументов шаблона: ошибка: нет типа с именем 'type' в 'struct std :: enable_if'

Как я могу сказать что-то вроде «пустого члена нет». вместо этого (например, со static_asserts)?


person user2081073    schedule 03.03.2013    source источник
comment
Извините, мне пришлось обновить заголовок .. И я нашел ЭТО ... выглядит почти правильно ...   -  person user2081073    schedule 03.03.2013


Ответы (1)


Хм, на самом деле enable_if не нужен, когда мне действительно нужна конкретная ошибка компилятора с static_assert, поэтому я придумал следующее решение:

//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))

Добавление вызова CHECK_HAS_MEMBER() в конец макроса CREATE_MEMBER_VAR_CHECK делает его еще более «читабельным».

person user2081073    schedule 03.03.2013
comment
Пожалуйста, внесите изменения в свой вопрос. Этот ваш пост не является ответом. - person Lightness Races in Orbit; 03.03.2013
comment
как это не ответ? - person user2081073; 03.03.2013
comment
Что-то не так с этим подходом? Или кто-нибудь видит лучшее решение? Это твой пост, нет? - person Lightness Races in Orbit; 03.03.2013
comment
Да, если бы я отредактировал вопрос, то все свелось бы к этому, правильно. Однако я действительно ответил на свой вопрос через 2 часа, и я не хочу, чтобы кто-то еще тратил свое время. (Вопрос о лучшем решении всегда подразумевается вместе с любым ответом на этом сайте, не так ли?) - person user2081073; 03.03.2013
comment
Хорошо, тогда да, это подразумевается в системе комментариев. Я отредактировал последний вопрос, чтобы было понятнее, что означает этот пост. Спасибо за ответ (что было правильно!) - person Lightness Races in Orbit; 03.03.2013