为什么这些条件不适用于模板类型?

why shouldn't these conditions work for template types?

本文关键字:类型 适用于 不适用 条件 为什么      更新时间:2023-10-16

正如我之前的问题一样,我试图构建一个条件来检查两种类型,检查我是否应该执行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将返回true!!!

 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会再次为(int, int)返回true,这是不可能的!!!

问题

1) 我没做错什么?

总结评论中给出的解决方案和答案:(感谢T.C.和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)), "...");

一个更好的解决方案,而不是更长的解决方案是创建一个自己的类型特征类:

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++语法,不需要额外的括号。