使用GCC编译没有RTTI的时间typeid

时间:2011-11-03 20:11:25

标签: c++ reflection

无论如何,在禁用RTTI的情况下从GCC获取编译时typeid信息?在Visual Studio下,即使禁用了RTTI,像const char* typeName = typeid(int).name();这样的简单命令也会适当地返回“int”。不幸的是,海湾合作委员会不能这样做。当我尝试在没有RTTI的情况下调用typeid时,我的程序崩溃了。我知道禁用RTTI不是标准的一部分,但无论如何我可以强迫GCC进行已知类型的编译时解析吗?

出于性能原因,RTTI已被禁用。我不需要运行时RTTI。

编辑:

这就是我最终的目标:

template<typename T> const char* TypeName(void);
template<typename T> const char* TypeName(T type) { return TypeName<T>(); }

#define REFLECTION_REGISTER_TYPE(type) \
    template <> const char* TypeName<type>(void) { return #type; } 

它要求为每个需要反射信息的类型调用REFLECTION_REGISTER_TYPE。但只要为每个必需类型调用它,调用TypeName<int>就能完美运行。我还添加了函数TypeName(T type),这意味着您可以执行以下操作:int x = 0; printf(TypeName(x));并且它将打印出“int”。 GCC应该能够像VC ++一样在编译时实现这一点。

6 个答案:

答案 0 :(得分:5)

没有。 RTTI是 RunTime 类型信息(并禁用它是愚蠢的,但是嘿),这就是typeid的目的。如果你想在编译时将类型名称串起来,你必须自己做(通过模板或宏)。

答案 1 :(得分:5)

首先,请转回RTTI。

如果你失败了,如果你真的 *真的*需要得到一个没有它的类型的字符串表示,带一点字符串操作,并仔细考虑你写的非如果您升级GCC,或更改平台或使用其他一组选项可能会破坏的标准代码,您可能会伪造它。

#include <iostream>
#include <string>

std::string extract_type_name(const char* s) {
  //add logic her
  return s;
}

template<typename T>
std::string type_name() {
  static std::string s = extract_type_name(__PRETTY_FUNCTION__);
  return s;
}

int main() {
  std::cout << type_name<int>() << " " << type_name<std::string>() << std::endl;
}

该功能在ideone上的输出是

std::string type_name() [with T = int]
std::string type_name() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]

假设__PRETTY_FUNCTION__在关闭RTTI的情况下表现相同,那么将T = blah位拖出来应该不会太困难。

另外,请记住,typeid(blah).name()提供的保证非常少......我记得在一个平台上使用它,其中任何用户定义类型的结果只是struct。没有太大的用处。即使启用了RTTI,依赖它也很脆弱[无论如何你都应该这样做]。

答案 2 :(得分:5)

还有另一种解决方案,其优点和缺点是:

typedef void* TypeId;
template<class T>
TypeId TypeIdNoRTTI() //this function is instantiated for every different type
{
    //WARNING: works only inside one module: same type coming from different module will have different value!
    static T* TypeUniqueMarker = NULL; //thus this static variable will be created for each TypeIdNoRTTI<T> separately
    return &TypeUniqueMarker; //it's address is unique identifier of TypeIdNoRTTI<T> type
}

答案 3 :(得分:1)

GCC支持使用typeof编译时间类型运算符。

答案 4 :(得分:0)

似乎至少有一位承认RTTI通常不可用的现实的开发人员认为拥有"compile time type information"是件好事。

“ ctti C ++”的搜索结果也更多,因此我希望有很多选项可以涵盖大部分有用和可能的内容。

注意:我从未使用过该库,因此使用后果自负。

答案 5 :(得分:0)

基于Kyle的编辑,他的解决方案有所变化。如果您拥有诸如arduino uno,nano,mega(或类似产品)之类的atmel avr avr 8位微控制器,则此解决方案很有用。这样的微控制器具有非常小的cpu和ram占用空间。定义和比较字符串效率不高。为了使其高效,需要枚举。

可悲的是,此解决方案有一个dependency(您只需要boost的预处理器部分)。类型可以在运行时进行比较。

文件get_type.h的内容:

#pragma once
#include <boost/preprocessor.hpp>

template<typename rtt_enum, typename T> rtt_enum getType(void);
template<typename rtt_enum, typename T> rtt_enum getType(T type) { return getType< rtt_enum, T>(); }

#define ENUM_ENTRY(r, data, elem) elem,
#define REFLECTION_REGISTER_TYPE(r, rtt_enum, rtt_type)\
    template <> rtt_enum getType<rtt_enum, rtt_type>(void) { return rtt_enum::rtt_type; }

#define REFLECTION_REGISTER(rtt_enum, rtt_list)\
    enum class rtt_enum {\
        BOOST_PP_SEQ_FOR_EACH(ENUM_ENTRY, ~, BOOST_PP_VARIADIC_TO_SEQ rtt_list)\
    };\
    BOOST_PP_SEQ_FOR_EACH(REFLECTION_REGISTER_TYPE, rtt_enum, BOOST_PP_VARIADIC_TO_SEQ rtt_list)

用法非常简单:

#include <Arduino.h>
#include "get_type.h"

class MyClass1 {};
class MyClass2 {};
REFLECTION_REGISTER(MyTypes1, (MyClass1, MyClass2))

class MyClass3 {};
class MyClass4 {};
REFLECTION_REGISTER(MyTypes2, (MyClass3, MyClass4))

void setup(){
    MyClass1 obj1;
    MyClass2 obj2;

    MyTypes1 t = getType<MyTypes1>(obj2);

    Serial.println((int)t); // will print "1", because MyClass2 is second elem in enum MyTypes1 

    switch(t){
    case MyTypes1::MyClass1:
        //do fancy stuff with MyClass1
    break;

    case MyTypes1::MyClass2:
        //do fancy stuff with MyClass2
    break;
    }
}

void loop(){}

如您所见,您甚至可以注册多组类型,例如MyTypes1或MyTypes2。

相关问题