是否有在不同版本的 g++ 编译器中使用 typeid 和 typeinfo 的解决方法?

问题描述 投票:0回答:1

我的程序使用

typeid()
typeinfo
在运行时检查这两种类型是否相同。

以下是一个最小的示例。


lib.h

#ifndef _ACANE_LIB_H_
#define _ACANE_LIB_H_

#include <typeinfo>
#include <typeindex>
#include <tuple>

std::type_index* GetTypeIndex();
const char* GetTypeIndexName();

#endif

lib.cpp

#include "lib.h"

#include <tuple>

std::type_index* GetTypeIndex() {
    return new std::type_index(typeid(std::tuple<int, int>));
}


const char* GetTypeIndexName() {
    return typeid(std::tuple<int, int>).name();
}

main.cpp

#include <cstdio>
#include <cstring>
#include <cxxabi.h>
#include <string>
#include <memory>
#include "lib.h"

static std::string Demangle(const char* name) {
  int status = -4;
  std::unique_ptr<char, void(*)(void*)> res {
      abi::__cxa_demangle(name, NULL, NULL, &status),
      std::free
  };
  return (status==0) ? res.get() : name ;
}

int main() {
    std::type_index target = std::type_index(typeid(std::tuple<int, int>));
    std::type_index* expected = GetTypeIndex();;
    if (target == *expected) {
        printf("yes\n");
    }
    else {
        printf("no\n");
    }

    const char* target_name = typeid(std::tuple<int, int>).name();
    const char* expected_name = GetTypeIndexName();
    if (!strcmp(target_name, expected_name)) {
        printf("yes\n");
    }
    else {
        printf("no\n");
        printf("target: %s\nexpected: %s\n", target_name, expected_name);
        std::string s1 = Demangle(target_name), s2 = Demangle(expected_name);
        printf("target: %s\nexpected: %s\n", target_name, expected_name);
        printf("target: %s\nexpected: %s\n", s1.c_str(), s2.c_str());
        printf("target: %p\nexpected: %p\n", target_name, expected_name);
    }
}

我将 lib.cpp 编译成静态库,并使用以下命令将 main.cpp 与其链接

build_with_same_compiler.sh

#!/bin/bash

LIB_CC=/usr/gcc-4.9.4/bin/g++
LIB_AR=/usr/gcc-4.9.4/bin/gcc-ar
EXEC_CC=/usr/gcc-4.9.4/bin/g++
CXX_FLAGS="-std=c++11"

set -x

$LIB_CC -fPIC -c lib.cpp -o lib.o -std=c++11 $CXX_FLAGS
$LIB_AR cr libtesttypeinfo.a lib.o

$EXEC_CC -c main.cpp -o main.o $CXX_FLAGS
$EXEC_CC -o main_same main.o -L. -ltesttypeinfo

它按我的预期工作(显然)。


但是当我用不同的编译器编译静态lib和main.cpp时,它不起作用。 typeid 返回不同的 type_info。

build_with_ different_compiler.sh

#!/bin/bash

LIB_CC=/usr/gcc-4.9.4/bin/g++
LIB_AR=/usr/gcc-4.9.4/bin/gcc-ar
# EXEC_CC=/usr/gcc-12.1/bin/g++
EXEC_CC=/usr/bin/g++-7
CXX_FLAGS="-std=c++11"

set -x

$LIB_CC -fPIC -c lib.cpp -o lib.o -std=c++11 $CXX_FLAGS
$LIB_AR cr libtesttypeinfo.a lib.o

$EXEC_CC -c main.cpp -o main.o $CXX_FLAGS
$EXEC_CC -o main_diff main.o -L. -ltesttypeinfo

输出是

no
no
target: St5tupleIJiiEE
expected: St5tupleIIiiEE
target: St5tupleIJiiEE
expected: St5tupleIIiiEE
target: std::tuple<int, int>
expected: std::tuple<int, int>
target: 0x5580ab7a36b8
expected: 0x5580ab7a374d

在 g++4.9.4 中,

std::tuple<int, int>
的名称是
St5tupleIJiiEE
,而在 g++7.5 中,它是
St5tupleIIiiEE

由于 type_info 是实现定义的,是否有任何解决方法和稳定的方法来在运行时检查类型?

还有一个问题是,C++17中的

std::any
也使用了type_info,
std::any
如何保证不同版本的编译器之间的type_info始终相同?

c++ g++
1个回答
2
投票

有没有任何解决方法和稳定的方法来在运行时检查类型?

不。事实上,对于相同的类型,typeid、typeinfo,尤其是

name()
每次运行相同的程序时都可以返回不同的值。

对于给定类型,您将在同一程序运行期间获得一致的结果。

下次程序运行时,记录会被清除。所有赌注都失败了。

还有一个问题是,C++17中的std::any也使用了type_info,那么std::any如何保证不同版本的编译器之间的type_info始终相同?

事实并非如此。它不需要。

std::any
比较的都是在同一程序运行期间创建的对象类型。这保证是一致的。 std::any 中没有任何类型的工具可以将特定对象的类型保存在某处,然后在后续程序运行期间将其取出以进行比较。
    

© www.soinside.com 2019 - 2024. All rights reserved.