سؤال

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

<اقتباس فقرة>   

خطأ إعراب example.txt. القيمة ( "notaninteger") من [MySectiom] مفتاح ليس كثافة صحيح

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

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

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));
    }
}

وإيد] بالأحرى يكن لديك لجعل الزائدة محددة لكل نوع التي قد تستخدم ملفات البيانات، لأن هناك الكثير من لهم ...

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

وتحرير: طيب هذا هو الحل خطرت لي:

ولدي 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 لفي ملفات حزب الشعب الكمبودي لكل نوع ولست بحاجة للتعامل مع (على سبيل المثال في ملف حزب الشعب الكمبودي التي تحدد نوع لتبدأ).

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

هل كانت مفيدة؟

المحلول

وحل جيسي Beder هو على الأرجح أفضل، ولكن إذا كنت لا تحب أسماء typeid يمنحك (على ما أظن دول مجلس التعاون الخليجي يعطيك أسماء المهترئ على سبيل المثال)، يمكنك أن تفعل شيئا مثل:

template<typename T>
struct TypeParseTraits;

#define REGISTER_PARSE_TYPE(X) template <> struct TypeParseTraits<X> \
    { static const char* name; } ; const char* TypeParseTraits<X>::name = #X


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

وثم استخدامه مثل

throw ParseError(TypeParseTraits<T>::name);

وتحرير:

ويمكن أيضا الجمع بين الأمرين، وتغير name أن تكون الوظيفة التي كتبها المكالمات الافتراضي typeid(T).name() ثم تتخصص فقط لتلك الحالات التي يكون فيها هذا غير مقبول.

نصائح أخرى

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

cppreference.com :

<اقتباس فقرة>   

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

     

...

     

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

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

#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;
}

وكما ذكر Bunkar typeid (T) .name هو تنفيذ محددة.

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

وعلى سبيل المثال:

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

والجواب من لوغان 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 ++ ملف ...

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

تعزيز مكتبة 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;
}

وأنا مجرد ترك الأمر هناك. اذا كان هناك من لا يزال في حاجة إليها، ثم يمكنك استخدام هذا:

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
.
.
.

وهذا سوف تحقق فقط اكتب لا تحصل عليه وإلا لنوع 1 أو 2.

إذا كنت ترغب في pretty_name حل لوغان Capaldo للا يمكن التعامل مع هيكل البيانات المعقدة: REGISTER_PARSE_TYPE(map<int,int>) وtypeid(map<int,int>).name() يعطيني نتيجة St3mapIiiSt4lessIiESaISt4pairIKiiEEE

وهناك إجابة أخرى مثيرة للاهتمام باستخدام unordered_map أو map تأتي من HTTPS: // داخلي. cppreference.com/w/cpp/types/type_index .

#include <iostream>
#include <unordered_map>
#include <map>
#include <typeindex>
using namespace std;
unordered_map<type_index,string> types_map_;

int main(){
    types_map_[typeid(int)]="int";
    types_map_[typeid(float)]="float";
    types_map_[typeid(map<int,int>)]="map<int,int>";

    map<int,int> mp;
    cout<<types_map_[typeid(map<int,int>)]<<endl;
    cout<<types_map_[typeid(mp)]<<endl;
    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top