C++ احصل على اسم النوع في القالب




templates compile-time (5)

أنا أكتب بعض فصول القوالب لتحليل بعض ملفات البيانات النصية ، وعلى هذا النحو ، فإن الغالبية العظمى من أخطاء التحليل تكون بسبب أخطاء في ملف البيانات ، والتي لا يتم كتابتها في الغالب من قبل المبرمجين ، وبالتالي رسالة لطيفة حول سبب فشل تحميل التطبيق ، على سبيل المثال:

خطأ في تحليل ملف example.txt. القيمة ("notaninteger") لمفتاح [MySectiom] غير صحيحة int

يمكنني عمل الملف والقسم وأسماء المفاتيح من الوسيطات التي تم تمريرها إلى وظيفة القالب والفارسية العضو في الصف ، ولكن لست متأكدًا من كيفية الحصول على اسم النوع الذي تحاول دالة القالب التحويل إليه.

يبدو شفرتي الحالية ، مع وجود تخصصات للسلاسل العادية فقط مثل:

template<typename T> T GetValue(const std::wstring &section, const std::wstring &key)
{
    std::map<std::wstring, std::wstring>::iterator it = map[section].find(key);
    if(it == map[section].end())
        throw ItemDoesNotExist(file, section, key)
    else
    {
        try{return boost::lexical_cast<T>(it->second);}
        //needs to get the name from T somehow
        catch(...)throw ParseError(file, section, key, it->second, TypeName(T));
    }
}

بدلاً من ذلك ، لا يتعين على "Id" أن تقوم بعمل زيادة في التحميل لكل نوع قد تستخدمه ملفات البيانات ، نظرًا لوجود كميات كبيرة منها ...

كما أحتاج إلى حل لا يتكبد أي نفقات تشغيلية ما لم يحدث استثناء ، أي أن حل وقت التجميع بالكامل هو ما أريده لأن هذا الكود يدعى أطنانًا من المرات ، وأوقات التحميل تكون أطول إلى حد ما.

تعديل: حسنًا ، هذا هو الحل الذي توصلت إليه:

لدي types.h containg ما يلي

#pragma once
template<typename T> const wchar_t *GetTypeName();

#define DEFINE_TYPE_NAME(type, name) \
    template<>const wchar_t *GetTypeName<type>(){return name;}

بعد ذلك ، يمكنني استخدام ماكرو DEFINE_TYPE_NAME في ملفات cpp لكل نوع أحتاج إلى التعامل معه (على سبيل المثال في ملف cpp الذي يحدد النوع للبدء به).

بعد ذلك ، يستطيع الرابط العثور على تخصص قالب appropirate طالما تم تعريفه في مكان ما ، أو رمي خطأ رابط بطريقة أخرى حتى أتمكن من إضافة النوع.


أنا فقط أتركها هناك. إذا كان هناك شخص ما سيظل بحاجة إليه ، فيمكنك استخدام هذا:

template <class T>
bool isString(T* t) { return false;  } // normal case returns false

template <>
bool isString(char* t) { return true; }  // but for char* or String.c_str() returns true
.
.
.

سيؤدي هذا فقط إلى التحقق من النوع وليس GET له ولنوع واحد أو 2 فقط.


إجابة Logan Capaldo صحيحة ولكن يمكن تبسيطها بشكل طفيف لأنه من غير الضروري تخصيص الصف الدراسي في كل مرة. يمكن للمرء أن يكتب:

// in header
template<typename T>
struct TypeParseTraits
{ static const char* name; };

// in c-file
#define REGISTER_PARSE_TYPE(X) \
    template <> const char* TypeParseTraits<X>::name = #X

REGISTER_PARSE_TYPE(int);
REGISTER_PARSE_TYPE(double);
REGISTER_PARSE_TYPE(FooClass);
// etc...

يسمح لك هذا أيضًا بوضع تعليمات REGISTER_PARSE_TYPE في ملف C ++ ...


كإعادة صياغة جواب أندريه:

يمكن استخدام مكتبة Boost TypeIndex لطباعة أسماء الأنواع.

داخل القالب ، قد يقرأ هذا كما يلي

#include <boost/type_index.hpp>
#include <iostream>

template<typename T>
void printNameOfType() {
    std::cout << "Type of T: " 
              << boost::typeindex::type_id<T>().pretty_name() 
              << std::endl;
}

كما ذكر Bunkar typeid (T) .name هو تعريف التنفيذ.

لتجنب هذه المشكلة ، يمكنك استخدام مكتبة Boost.TypeIndex .

فمثلا:

boost::typeindex::type_id<T>().pretty_name() // human readable

typeid(T).name() يتم تعريف التنفيذ ولا يضمن سلسلة مقروءة الإنسان.

قراءة cppreference.com :

تقوم بإرجاع سلسلة أحرف محددة تم إنهاؤها خالية من التطبيق تحتوي على اسم النوع. يتم إعطاء أي ضمانات ، على وجه الخصوص ، يمكن أن تكون السلسلة التي تم إرجاعها متطابقة لعدة أنواع والتغيير بين دعوات من نفس البرنامج.

...

باستخدام برامج التحويل البرمجي مثل gcc و clang ، يمكن تمرير السلسلة التي تم إرجاعها خلال c ++ filt -t ليتم تحويلها إلى نموذج قابل للقراءة.

لكن في بعض الحالات ، لا يعرض مجلس التعاون الخليجي السلسلة الصحيحة. على سبيل المثال على الجهاز الخاص بي لدي gcc whith -std=c++11 و typeid(T).name() دالة القالب typeid(T).name() إرجاع "j" لـ "unsigned int" . يطلق عليه اسم mangled. للحصول على اسم النوع الحقيقي ، استخدم الدالة abi::__cxa_demangle() (gcc فقط):

#include <string>
#include <cstdlib>
#include <cxxabi.h>

template<typename T>
std::string type_name()
{
    int status;
    std::string tname = typeid(T).name();
    char *demangled_name = abi::__cxa_demangle(tname.c_str(), NULL, NULL, &status);
    if(status == 0) {
        tname = demangled_name;
        std::free(demangled_name);
    }   
    return tname;
}




typename