2015-03-31 2 views
0

Как мой previous question Я пытаюсь построить условия для проверки двух типов проверки, следует ли мне делать dynamic_cast или нет. я следующие условия:Почему эти условия не должны работать для типов шаблонов?

#define can_dynamic_cast(FROM, TO) \ 
           can_cast(FROM, TO) && \ 
           !std::is_same<FROM, TO>::value && \ 
           std::is_class<TO>::value && \ 
           !std::is_const<FROM>::value && \ 
           std::is_base_of<TO, FROM>::value 

Это не работает ниже базовой проверки, то can_dynamic_cast возвращает истину !!!

static_assert(!can_dynamic_cast(int, int), "didn't expecting dynamic cast, but could!") 

Из отчаяния я спустился до нижних условий, но все еще не надеялся!

#define can_dynamic_cast(FROM, TO) \ 
            std::is_convertible<FROM, TO>::value && \ 
            std::is_class<TO>::value && \ 
            std::is_class<FROM>::value 

Приведенные выше условия являются наиболее основные условия, can_dynamic_cast вернутся true для (int, int) снова, что не предполагаем !!!

Вопрос

1) Что я не ошибаюсь?

+6

Попробуйте развернуть свой макрос вручную. Подсказка: это '!' Не применяется ко всему выражению. –

+0

@Brian Но тип назначения должен быть указателем/ссылкой на полный тип класса или указатель на cv void. –

+0

@ T.C. Ой, ты прав. Я пропустил это. – Brian

ответ

0

Резюмируя решения и ответы, приведенные в комментариях: (Спасибо Агар Т.С. и AntonSavin)

Ваш макрос не совсем так, но это макрос. Препроцессор просто заменяет макро-вызов с содержанием макроса:

static_assert(!can_dynamic_cast(int, int), "..."); 
// => 
static_assert(!std::is_convertible<int, int>::value && 
       std::is_class<int>::value && 
       std::is_class<int>::value , "..."); 

Таким образом, только первое значение отрицается, и это производит неожиданное поведение.

Чтобы преодолеть эту проблему, вы должны добавить скобки, либо в определении макроса, или при вызове макроса:

#define can_dynamic_cast(FROM, TO) \ 
     (std::is_convertible<FROM, TO>::value && \ 
      std::is_class<TO>::value && \ 
      std::is_class<FROM>::value) 
// or 

static_assert(!(can_dynamic_cast(int, int)), "..."); 

лучшим решением, и не намного больше решений является создание собственного типа -traits класс:

template <class FROM, class TO> 
struct can_dynamic_cast : std::integral_constant< bool, 
    std::is_convertible<FROM, TO>::value && 
    std::is_class<TO>::value && 
    std::is_class<FROM>::value > {}; 

static_assert(!can_dynamic_cast<int, int>::value, "..."); 

он менее подвержен ошибкам, так как это следует C++ синтаксис вызова мета-функции и не требуется никаких дополнительных кронштейнов.

Смежные вопросы