类型应该相同但不是

问题描述

我不确定我是否理解为什么第一个测试结果为真,第二个结果为假。我知道来自 typeid().name() 的信息通常不可靠,但我的主要问题在于 typeid 本身。我不明白为什么 *test 的类型不是 Location<1>,或者还有什么问题。有什么想法吗?在这里我看不到的类型是否有相同的包装器?提前致谢,如果答案显而易见,我们深表歉意。

#include <iostream>
#include <utility>
#include <typeinfo>

class LocationAbstract
{
    virtual void get_() = 0;
};

template<int i>
class Location : public LocationAbstract
{
public:
    static constexpr int test = i;
    
    virtual void get_() override
    {
        return;
    }
};

template <int i>
Location<i> LocationGenerator()
{
    Location<i> test{};
    
    return test;
    
}

int main()
{
    LocationAbstract *table[10];
    
    table[0] = new decltype(LocationGenerator<0>());
    table[1] = new decltype(LocationGenerator<1>());
    
    Location<1> *test;
    
    try
    {
        std::cout << "Casting\n";
        test = dynamic_cast<Location<1>*>(table[1]);
    }
    catch (std::bad_cast &e)
    {
        std::cout << "Bad cast\n";
    }
    
    // test1,evaluates to true
    std::cout << (typeid(*test) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
    std::cout << typeid(*test).name() << "\n";
    std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n----\n";
    
    // test2,why does this evaluate to false while the above evaluates to true ?
    std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
    std::cout << typeid((Location<1>())).name() << "\n";
    std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n";

    auto test1 = Location<1>();
    auto test2 = *dynamic_cast<Location<1>*>(table[1]);
    
    std::cout << typeid(test1).name() << " and " << typeid(test2).name() << "\n";

    return 0;
}

解决方法

额外的一组 () 在这里变得与众不同。在 typeid(Location<1>())typeid((Location<1>())) 中,Location<1>() 实际上意味着两个完全不同的东西。

typeid(Location<1>()) 中,Location<1>() 被解释为返回 Location<1> 且不带参数的函数类型。

typeid((Location<1>())) 中,Location<1>() 被解释为对匿名 Location<1> 对象进行值初始化。

typeid 运算符可用于类型或表达式。也就是说,您可以说 typeid(int)typeid(42)。由于 Location<1>() 可以 被解释为一种类型,因此该语言是这样做的。 (Location<1>()) 不能解释为类型,所以它必须解释为表达式。作为表达式的一部分,Location<1>() 的唯一含义是对匿名 Location<1> 对象进行值初始化,因此 typeid 为您提供该对象的类型。


让这成为创建临时对象时更喜欢统一初始化语法的另一个原因; Location<1>{} 不会有这种歧义。

,

检查这两行:

std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid((Location<1>())).name() << "\n";

在第一行中,您使用 typeid(Location<1>())typeid 可以接受类型也可以接受表达式,Location<1>() 是一种没有参数的函数类型,返回类型为 Location<1>

那为什么打印出来的名字是一样的呢?那是因为第二行:typeid((Location<1>()))。通过将参数括在括号中,它不再是有效类型,因此将其视为表达式并打印 typeid(Location<1>) 的名称。删除额外的括号会在相同的修改方案下打印 F8LocationILi1EEvE

为了避免歧义,您也可以直接使用类型(typeid(Location<1>))或使用大括号:typeid(Location<1>{}))。