স্ট্যান্ডার্ড সি ++ তে কোনও ভেরিয়েবলের প্রিন্ট মুদ্রণ করা সম্ভব?


393

উদাহরণ স্বরূপ:

int a = 12;
cout << typeof(a) << endl;

প্রত্যাশিত আউটপুট:

int

2
এখানে হাওয়ার্ড দীর্ঘ ফর্ম সমাধান একটি সারসংক্ষেপ কিন্তু একটি খারেজি এক লাইন ম্যাক্রো সঙ্গে বাস্তবায়িত: #define DEMANGLE_TYPEID_NAME(x) abi::__cxa_demangle(typeid((x)).name(), NULL, NULL, NULL)। আপনি ক্রস-প্ল্যাটফর্ম সমর্থন প্রয়োজন: ব্যবহারের #ifdef, #else, #endifMSVC মত অন্যান্য প্ল্যাটফর্মের জন্য এক ম্যাক্রো প্রদান।
ট্রেভর বয়ড স্মিথ

অনেক বেশী সুনিদৃষ্ট মানুষের পাঠযোগ্য প্রয়োজনের সাথে: stackoverflow.com/questions/12877521/...
সিরো Santilli郝海东冠状病六四事件法轮功

3
আপনি যদি এটি কেবল ডিবাগিংয়ের জন্য ব্যবহার করেন তবে আপনি বিবেচনা করতে পারেন template<typename T> void print_T() { std::cout << __PRETTY_FUNCTION__ << '\n'; }। তারপরে উদাহরণস্বরূপ ব্যবহারটি রানটাইমের সময়ে print_T<const int * const **>();মুদ্রণ করবে void print_T() [T = const int *const **]এবং সমস্ত যোগ্যতা সংরক্ষণ করবে (জিসিসি এবং কলংয়ে কাজ করে)।
হেনরি মেনকে

@ হেনরি, __PRETTY_FUNCTION__স্ট্যান্ডার্ড সি ++ নয় (প্রয়োজনীয় প্রশ্নের শিরোনামে রয়েছে)।
টবি স্পিড

উত্তর:


505

খুব পুরানো প্রশ্নের সি ++ 11 আপডেট: সি ++ এ ভেরিয়েবল প্রিন্ট করুন।

গৃহীত (এবং ভাল) উত্তরটি হ'ল ব্যবহার করা typeid(a).name(), যেখানে aএকটি পরিবর্তনশীল নাম।

এখন C ++ 11 এ আমাদের রয়েছে decltype(x), যা একটি অভিব্যক্তিটিকে এক প্রকারে রূপান্তর করতে পারে। এবং decltype()এটি খুব আকর্ষণীয় নিয়মের নিজস্ব সেট নিয়ে আসে। উদাহরণস্বরূপ decltype(a)এবং decltype((a))সাধারণত বিভিন্ন ধরণের হবে (এবং ভাল এবং বোধগম্য কারণে এই কারণগুলি প্রকাশিত হওয়ার পরে)।

আমাদের বিশ্বস্তরা কি আমাদের typeid(a).name()এই সাহসী নতুন বিশ্বকে অন্বেষণ করতে সহায়তা করবে ?

না।

তবে যে সরঞ্জামটি তা জটিল নয়। এবং এটি সেই সরঞ্জামটি যা আমি এই প্রশ্নের উত্তর হিসাবে ব্যবহার করছি। আমি এই নতুন সরঞ্জামটির সাথে তুলনা করব এবং তার বিপরীতে করব typeid(a).name()। এবং এই নতুন সরঞ্জামটি আসলে উপরে তৈরি করা হয়েছে typeid(a).name()

মূল বিষয়:

typeid(a).name()

সিভি-কোয়ালিফায়ার, রেফারেন্স এবং লভ্যালু / র্যালু-নেস দূরে ফেলে দেয়। উদাহরণ স্বরূপ:

const int ci = 0;
std::cout << typeid(ci).name() << '\n';

আমার ফলাফল:

i

এবং আমি এমএসভিসি ফলাফলগুলি অনুমান করছি:

int

অর্থাৎ constচলে গেছে। এটি কোন কিউআই (বাস্তবায়নের মান) সমস্যা নয়। মান এই আচরণকে আদেশ দেয়।

আমি নীচে যা সুপারিশ করছি তা হ'ল:

template <typename T> std::string type_name();

যা এ জাতীয়ভাবে ব্যবহৃত হবে:

const int ci = 0;
std::cout << type_name<decltype(ci)>() << '\n';

এবং আমার ফলাফল:

int const

<disclaimer>আমি এমএসভিসিতে এটি পরীক্ষা করিনি। </disclaimer> তবে আমি যারা তাদের কাছ থেকে প্রতিক্রিয়া স্বাগত জানাই।

সি ++ 11 সমাধান

ডিমাপল প্রকারের উত্তরটিতে আইপ্যাডডপের__cxa_demangle পরামর্শ অনুযায়ী আমি নন-এমএসভিসি প্ল্যাটফর্মগুলির জন্য ব্যবহার করছি । তবে এমএসভিসিতে আমি নামগুলি ডিমেংল করতে (অনির্ধারিত) বিশ্বাস করি । এবং এই কোরটি এমন কিছু সাধারণ পরীক্ষার চারপাশে মোড়ানো যা সিভি-কোয়ালিফায়ার এবং ইনপুট ধরণের রেফারেন্সগুলি সনাক্ত করে, পুনরুদ্ধার করে এবং প্রতিবেদন করে।typeid

#include <type_traits>
#include <typeinfo>
#ifndef _MSC_VER
#   include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>

template <class T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
#ifndef _MSC_VER
                abi::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
#else
                nullptr,
#endif
                std::free
           );
    std::string r = own != nullptr ? own.get() : typeid(TR).name();
    if (std::is_const<TR>::value)
        r += " const";
    if (std::is_volatile<TR>::value)
        r += " volatile";
    if (std::is_lvalue_reference<T>::value)
        r += "&";
    else if (std::is_rvalue_reference<T>::value)
        r += "&&";
    return r;
}

ফলাফলগুলো

এই সমাধানের সাথে আমি এটি করতে পারি:

int& foo_lref();
int&& foo_rref();
int foo_value();

int
main()
{
    int i = 0;
    const int ci = 0;
    std::cout << "decltype(i) is " << type_name<decltype(i)>() << '\n';
    std::cout << "decltype((i)) is " << type_name<decltype((i))>() << '\n';
    std::cout << "decltype(ci) is " << type_name<decltype(ci)>() << '\n';
    std::cout << "decltype((ci)) is " << type_name<decltype((ci))>() << '\n';
    std::cout << "decltype(static_cast<int&>(i)) is " << type_name<decltype(static_cast<int&>(i))>() << '\n';
    std::cout << "decltype(static_cast<int&&>(i)) is " << type_name<decltype(static_cast<int&&>(i))>() << '\n';
    std::cout << "decltype(static_cast<int>(i)) is " << type_name<decltype(static_cast<int>(i))>() << '\n';
    std::cout << "decltype(foo_lref()) is " << type_name<decltype(foo_lref())>() << '\n';
    std::cout << "decltype(foo_rref()) is " << type_name<decltype(foo_rref())>() << '\n';
    std::cout << "decltype(foo_value()) is " << type_name<decltype(foo_value())>() << '\n';
}

এবং আউটপুটটি হ'ল:

decltype(i) is int
decltype((i)) is int&
decltype(ci) is int const
decltype((ci)) is int const&
decltype(static_cast<int&>(i)) is int&
decltype(static_cast<int&&>(i)) is int&&
decltype(static_cast<int>(i)) is int
decltype(foo_lref()) is int&
decltype(foo_rref()) is int&&
decltype(foo_value()) is int

নোট (উদাহরণস্বরূপ) মধ্যে পার্থক্য decltype(i)এবং decltype((i))। প্রাক্তন ধরনের ঘোষণা এর i। পরবর্তীটি হ'ল অভিব্যক্তির "প্রকার" i। (এক্সপ্রেশন কখনই রেফারেন্স টাইপ থাকে না, তবে একটি সম্মেলন হিসাবে decltypeলভ্যালু রেফারেন্স সহ লভালু এক্সপ্রেশন উপস্থাপন করে)।

decltypeআপনার নিজের কোড অন্বেষণ এবং ডিবাগ করা ছাড়াও এই সরঞ্জামটি সম্পর্কে জানার জন্য একটি দুর্দান্ত বাহন ।

বিপরীতে, আমি typeid(a).name()হারানো সিভি-কোয়ালিফায়ার বা রেফারেন্সগুলি যোগ না করে যদি কেবল এটি তৈরি করতে চাই তবে আউটপুটটি হ'ল:

decltype(i) is int
decltype((i)) is int
decltype(ci) is int
decltype((ci)) is int
decltype(static_cast<int&>(i)) is int
decltype(static_cast<int&&>(i)) is int
decltype(static_cast<int>(i)) is int
decltype(foo_lref()) is int
decltype(foo_rref()) is int
decltype(foo_value()) is int

অর্থাত্ প্রতিটি রেফারেন্স এবং সিভি-কোয়ালিফায়ার ছিনিয়ে নেওয়া হয়।

সি ++ 14 আপডেট

কেবল যখন আপনি মনে করেন যে আপনি পেরেছেন এমন কোনও সমস্যার সমাধান পেয়েছেন, কেউ সর্বদা কোথাও কোথাও থেকে আসে না এবং আপনাকে আরও অনেক ভাল উপায় দেখায়। :-)

এই উত্তরটি থেকে আনন্দ-সম্মেলন দেখায় কিভাবে কম্পাইল সময়ে C ++ 14 টাইপ নাম জন্য। এটি বেশ কয়েকটি কারণে একটি উজ্জ্বল সমাধান:

  1. এটি সংকলন সময়ে!
  2. আপনি একটি লাইব্রেরির পরিবর্তে (এমনকি একটি std :: lib) কাজটি করার জন্য নিজেই সংকলকটি পাবেন। এর অর্থ সর্বশেষ ভাষার বৈশিষ্ট্যগুলির জন্য আরও সঠিক ফলাফল (যেমন ল্যাম্বডাস)।

জাম্বোরীর উত্তরটি ভিএস-এর পক্ষে পুরোপুরি কার্যকর হয় না এবং আমি তার কোডটি কিছুটা টুইট করছি twe তবে যেহেতু এই উত্তরটি প্রচুর মতামত পেয়েছে, তাই সেখানে যাওয়ার জন্য কিছুটা সময় নিন এবং তার উত্তরটিকে উপরে তুলে ধরুন, যা ছাড়া এই আপডেটটি কখনও ঘটেনি।

#include <cstddef>
#include <stdexcept>
#include <cstring>
#include <ostream>

#ifndef _MSC_VER
#  if __cplusplus < 201103
#    define CONSTEXPR11_TN
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN
#  elif __cplusplus < 201402
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN noexcept
#  else
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN constexpr
#    define NOEXCEPT_TN noexcept
#  endif
#else  // _MSC_VER
#  if _MSC_VER < 1900
#    define CONSTEXPR11_TN
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN
#  elif _MSC_VER < 2000
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN noexcept
#  else
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN constexpr
#    define NOEXCEPT_TN noexcept
#  endif
#endif  // _MSC_VER

class static_string
{
    const char* const p_;
    const std::size_t sz_;

public:
    typedef const char* const_iterator;

    template <std::size_t N>
    CONSTEXPR11_TN static_string(const char(&a)[N]) NOEXCEPT_TN
        : p_(a)
        , sz_(N-1)
        {}

    CONSTEXPR11_TN static_string(const char* p, std::size_t N) NOEXCEPT_TN
        : p_(p)
        , sz_(N)
        {}

    CONSTEXPR11_TN const char* data() const NOEXCEPT_TN {return p_;}
    CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN {return sz_;}

    CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN {return p_;}
    CONSTEXPR11_TN const_iterator end()   const NOEXCEPT_TN {return p_ + sz_;}

    CONSTEXPR11_TN char operator[](std::size_t n) const
    {
        return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
    }
};

inline
std::ostream&
operator<<(std::ostream& os, static_string const& s)
{
    return os.write(s.data(), s.size());
}

template <class T>
CONSTEXPR14_TN
static_string
type_name()
{
#ifdef __clang__
    static_string p = __PRETTY_FUNCTION__;
    return static_string(p.data() + 31, p.size() - 31 - 1);
#elif defined(__GNUC__)
    static_string p = __PRETTY_FUNCTION__;
#  if __cplusplus < 201402
    return static_string(p.data() + 36, p.size() - 36 - 1);
#  else
    return static_string(p.data() + 46, p.size() - 46 - 1);
#  endif
#elif defined(_MSC_VER)
    static_string p = __FUNCSIG__;
    return static_string(p.data() + 38, p.size() - 38 - 7);
#endif
}

constexprআপনি এখনও প্রাচীন সি ++ 11 এ আটকে থাকলে এই কোডটি অটো-ব্যাক অফ করবে । এবং আপনি যদি C ++ 98/03 দিয়ে গুহার দেয়ালে চিত্র আঁকেন, তবে noexceptপাশাপাশি কোরবানি দেওয়া হয়।

সি ++ 17 আপডেট

নীচের মন্তব্যে লাইবার্তা উল্লেখ করেছেন যে নতুনটিstd::string_view প্রতিস্থাপন করতে পারে static_string:

template <class T>
constexpr
std::string_view
type_name()
{
    using namespace std;
#ifdef __clang__
    string_view p = __PRETTY_FUNCTION__;
    return string_view(p.data() + 34, p.size() - 34 - 1);
#elif defined(__GNUC__)
    string_view p = __PRETTY_FUNCTION__;
#  if __cplusplus < 201402
    return string_view(p.data() + 36, p.size() - 36 - 1);
#  else
    return string_view(p.data() + 49, p.find(';', 49) - 49);
#  endif
#elif defined(_MSC_VER)
    string_view p = __FUNCSIG__;
    return string_view(p.data() + 84, p.size() - 84 - 7);
#endif
}

আমি নীচের মন্তব্যে জিভ ড্যাডসনের খুব সুন্দর গোয়েন্দা কাজের জন্য ভিএস ধন্যবাদটির জন্য ধ্রুবকগুলি আপডেট করেছি।

হালনাগাদ:

নীচে এই পুনর্লিখনটি পরীক্ষা করে দেখুন যা আমার সর্বশেষ সূচনায় অপঠনযোগ্য যাদু নম্বরগুলি সরিয়ে দেয়।


4
ভিএস 14 সিটিপি সঠিক প্রিন্ট করা হয়েছে, আমাকে কেবল একটি #include <iostream>লাইন যুক্ত করতে হয়েছিল ।
সর্বাধিক গ্যালকিন

3
কেন টেমপ্লেট <টাইপনেম টি> এসটিডি :: স্ট্রিং টাইপ_নাম ()? আপনি যুক্তি হিসাবে কোনও ধরণের পাস করছেন না কেন?
moonman239

2
আমি বিশ্বাস করি যে আমার যুক্তিটি ছিল যে আমার মাঝে মাঝে কেবলমাত্র একটি টাইপ ছিল (যেমন একটি ছাড়যোগ্য টেম্পলেট প্যারামিটার), এবং টাইপটি পেতে আমি তাদের মধ্যে একটির কৃত্রিমভাবে নির্মাণ করতে চাইনি (যদিও এই দিনগুলি declvalকাজ করবে)।
হাওয়ার্ড হিন্যান্ট

5
@ অ্যাঞ্জেলাসমর্টিস: সি ++ কোডের তুলনায় ইংরেজী অস্পষ্ট / অস্পষ্ট, তাই আপনার আগ্রহের যে নির্দিষ্ট ধরণের এবং আপনার আগ্রহী সেই নির্দিষ্ট সংকলক সহ আপনার পরীক্ষার ক্ষেত্রে এটি অনুলিপি / পেস্ট করতে উত্সাহিত করছি এবং আরও লিখুন ফলাফল বিস্ময়কর এবং / বা অসন্তুষ্টিজনক হলে বিশদ।
হাওয়ার্ড হিন্নন্ত

3
@ হাওয়ার্ডহিন্যান্ট আপনি কি এর std::string_viewপরিবর্তে ব্যবহার করতে পারবেন static_string?
লাইবার্তা

231

চেষ্টা করুন:

#include <typeinfo>

// …
std::cout << typeid(a).name() << '\n';

এটি কাজ করার জন্য আপনাকে আপনার সংকলক বিকল্পগুলিতে আরটিটিআই সক্রিয় করতে হতে পারে। অতিরিক্তভাবে, এর আউটপুট সংকলকটির উপর নির্ভর করে। এটি কোনও কাঁচা টাইপের নাম বা একটি নাম ম্যাংলিং প্রতীক বা এর মধ্যবর্তী কিছু হতে পারে।


4
নাম () ফাংশন দিয়ে স্ট্রিংটি ফিরিয়ে দেওয়া বাস্তবায়নকে সংজ্ঞায়িত করা হয় কেন?
ধ্বংসকারী

4
@ প্রবাসীমিট, যতদূর আমি জানি কোনও ভাল কারণ নেই। কমিটি সহজেই সংকলক বাস্তবায়নকারীদের নির্দিষ্ট প্রযুক্তিগত দিকগুলিতে বাধ্য করতে চায় নি - সম্ভবত ভুলত্রুটির মধ্যে।
কনরাড রুডল্ফ

2
আরটিটিআই সক্ষম করতে আমি কী পতাকা ব্যবহার করতে পারি? হতে পারে আপনি নিজের উত্তরকে অন্তর্ভুক্ত করতে পারেন।
জিম

4
@ পরিচালক একজন মানসম্পন্ন নাম ম্যাংলিং ফর্ম্যাটটি প্রদান করলে এই ধারণাটি পাওয়া যায় যে দুটি ভিন্ন সংকলক দ্বারা নির্মিত বাইনারিগুলির মধ্যে আন্তঃক্ষমতা সম্ভব এবং / অথবা নিরাপদ, যখন তা না হয়। যেহেতু সি ++ এর স্ট্যান্ডার্ড এবিআই নেই, একটি স্ট্যান্ডার্ড নেম ম্যাংলিং স্কিম অর্থহীন এবং সম্ভাব্য বিভ্রান্তিকর এবং বিপজ্জনক।
এলকভিস

1
@ জিম সংকলক পতাকাগুলির বিভাগটি উত্তরটির চেয়ে দীর্ঘতর আকারের ক্রম হবে। জিসিসি এটির সাথে ডিফল্টরূপে সংকলন করে, তাই "-fno-rtti", অন্যান্য সংকলকরা এটি না বেছে নিতে পারে তবে সংকলক পতাকার জন্য কোনও মান নেই।
কেএফসনে

82

খুব কুরুচিপূর্ণ তবে কৌশলটি যদি আপনি কেবল সময়ের তথ্য (উদাহরণস্বরূপ ডিবাগিংয়ের জন্য) চান:

auto testVar = std::make_tuple(1, 1.0, "abc");
decltype(testVar)::foo= 1;

রিটার্নস:

Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:5:19: error: 'foo' is not a member of 'std::tuple<int, double, const char*>'

2
কেবল সি ++ এটিকে এত কঠিন করে তুলতে পারে (সংকলনের সময় একটি স্বয়ংক্রিয় ভেরিয়েবল প্রিন্ট করা)। কেবলমাত্র সি ++।
কার্ল পিকেট

3
@ কার্লপ ঠিকঠাক হওয়া ভাল যে এটি কিছুটা auto testVar = std::make_tuple(1, 1.0, "abc"); decltype(testVar)::foo = 1;
বিশৃঙ্খলাবদ্ধ

ভিসি ++ ১ On-তে, এটি ফরওয়ার্ডিং-রেফারেন্স প্যারামিটার সহ কোনও টেম্পলেট ফাংশনে এমনকি প্লেইন রেফারেন্সের সাথে কোনও মূল্য-রেফারেন্স হ্রাস করে এবং স্ট্যান্ড :: ফরওয়ার্ডে মোড়ানো বস্তুর নাম।
জীভ ড্যাডসন

কোনও নতুন চাকা তৈরি না করে আপনি টাইপটিতে যেতে সক্ষম হয়েছিলেন!
স্টিভেন এ্যাকহফ

1
এই প্রযুক্তিটি কার্যকর আই সি ++ এ "আইটেম 4: ছাড়যোগ্য প্রকারগুলি কীভাবে দেখতে হয় তা জানুন" তেও বর্ণিত হয়েছে
আই

54

অন্তর্ভুক্ত করতে ভুলবেন না <typeinfo>

আমি বিশ্বাস করি আপনি যা উল্লেখ করছেন তা রানটাইম টাইপ শনাক্তকরণ। আপনি উপরোক্ত কাজগুলি করে অর্জন করতে পারেন।

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
  int i;
  cout << typeid(i).name();
  return 0;
}

36

হাওয়ার্ডের সমাধান অনুসারে , আপনি যদি যাদু নম্বরটি না চান তবে আমি মনে করি এটি উপস্থাপনের জন্য এটি একটি ভাল উপায় এবং স্বজ্ঞাত দেখায়:

#include <string_view>

template <typename T>
constexpr std::string_view 
type_name()
{
    std::string_view name, prefix, suffix;
#ifdef __clang__
    name = __PRETTY_FUNCTION__;
    prefix = "std::string_view type_name() [T = ";
    suffix = "]";
#elif defined(__GNUC__)
    name = __PRETTY_FUNCTION__;
    prefix = "constexpr std::string_view type_name() [with T = ";
    suffix = "; std::string_view = std::basic_string_view<char>]";
#elif defined(_MSC_VER)
    name = __FUNCSIG__;
    prefix = "class std::basic_string_view<char,struct std::char_traits<char> > __cdecl type_name<";
    suffix = ">(void)";
#endif
    name.remove_prefix(prefix.size());
    name.remove_suffix(suffix.size());
    return name;
}

4
এটি অতীত বেশ কয়েকটি সি ++ সংস্করণকে স্বল্প এবং মিষ্টি এমন কিছুতে প্রচেষ্টার দুর্দান্ত পাতন। +1 টি।
einpoklum

1
এটি আমার খুব প্রিয়!
হাওয়ার্ড হিনান্ট

1
এখানে একটি অনুরূপ ফাংশন যা আমি ব্যবহার, যে সনাক্ত করে প্রত্যয় / উপসর্গ স্বয়ংক্রিয়ভাবে: stackoverflow.com/questions/1055452/...
HolyBlackCat

22

মনে রাখবেন যে সি ++ এর আরটিটিআই বৈশিষ্ট্য দ্বারা উত্পাদিত নামগুলি পোর্টেবল নয় । উদাহরণস্বরূপ, ক্লাস

MyNamespace::CMyContainer<int, test_MyNamespace::CMyObject>

নিম্নলিখিত নামগুলি থাকবে:

// MSVC 2003:
class MyNamespace::CMyContainer[int,class test_MyNamespace::CMyObject]
// G++ 4.2:
N8MyNamespace8CMyContainerIiN13test_MyNamespace9CMyObjectEEE

সুতরাং আপনি এই তথ্যটি সিরিয়ালকরণের জন্য ব্যবহার করতে পারবেন না। তবে এখনও, টাইপড (ক) .নম () সম্পত্তিটি এখনও লগ / ডিবাগের উদ্দেশ্যে ব্যবহৃত হতে পারে


19

আপনি টেমপ্লেট ব্যবহার করতে পারেন।

template <typename T> const char* typeof(T&) { return "unknown"; }    // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(float&) { return "float"; }

উপরের উদাহরণে, যখন টাইপটি মেলে না তবে এটি "অজানা" মুদ্রণ করবে।


3
এটি শর্টস এবং চরগুলির জন্য "ইনট" মুদ্রণ করবে না? এবং "ভাসা" ডাবলসের জন্য?
গার্টেনরিজ

1
@gartenriese বিশেষায়নের যে অপূর্ণতা নেই। কারণ doubleএটি বিশেষায়িতকরণটি ব্যবহারের জন্য একটি অন্তর্নিহিত ধরণের রূপান্তর না করে টেমপ্লেট ফাংশনের অ-বিশেষায়িত সংস্করণ সংকলন করবে: cpp.sh/2wzc
chappjc

1
@ চাপজজ্যাক: আমি কেন সত্যিই জানি না কেন আমি তখনই এটি জিজ্ঞাসা করেছি, এটি এখন আমার কাছে বেশ স্পষ্ট। তবে যাইহোক যাইহোক এক বছরের পুরানো প্রশ্নের উত্তর দেওয়ার জন্য ধন্যবাদ!
গার্টেনরিজ

2
@ গার্টেনরিজ আমি যতটা অনুভূত হয়েছিলাম, তবে "ইন্টারনেট" কোনও কোনও ক্ষেত্রে একই প্রশ্ন থাকতে পারে।
chappjc

18

উল্লিখিত হিসাবে, typeid().name()একটি মঙ্গলযুক্ত নাম ফিরে আসতে পারে। জিসিসিতে (এবং কিছু অন্যান্য সংকলক) আপনি নিম্নলিখিত কোড সহ এটিকে ঘিরে কাজ করতে পারেন:

#include <cxxabi.h>
#include <iostream>
#include <typeinfo>
#include <cstdlib>

namespace some_namespace { namespace another_namespace {

  class my_class { };

} }

int main() {
  typedef some_namespace::another_namespace::my_class my_type;
  // mangled
  std::cout << typeid(my_type).name() << std::endl;

  // unmangled
  int status = 0;
  char* demangled = abi::__cxa_demangle(typeid(my_type).name(), 0, 0, &status);

  switch (status) {
    case -1: {
      // could not allocate memory
      std::cout << "Could not allocate memory" << std::endl;
      return -1;
    } break;
    case -2: {
      // invalid name under the C++ ABI mangling rules
      std::cout << "Invalid name" << std::endl;
      return -1;
    } break;
    case -3: {
      // invalid argument
      std::cout << "Invalid argument to demangle()" << std::endl;
      return -1;
    } break;
 }
 std::cout << demangled << std::endl;

 free(demangled);

 return 0;

}


10

আপনি এটির জন্য একটি বৈশিষ্ট্য শ্রেণি ব্যবহার করতে পারেন। কিছুটা এইরকম:

#include <iostream>
using namespace std;

template <typename T> class type_name {
public:
    static const char *name;
};

#define DECLARE_TYPE_NAME(x) template<> const char *type_name<x>::name = #x;
#define GET_TYPE_NAME(x) (type_name<typeof(x)>::name)

DECLARE_TYPE_NAME(int);

int main()
{
    int a = 12;
    cout << GET_TYPE_NAME(a) << endl;
}

দ্য DECLARE_TYPE_NAMEসব ধরনের আপনার যা দরকার আশা এই বৈশিষ্ট্যগুলো বর্গ ঘোষণা আপনার জীবন সহজ করতে বিদ্যমান নির্ধারণ করুন।

জড়িত সমাধানগুলির চেয়ে এটি আরও কার্যকর হতে পারে typeidকারণ আপনি আউটপুট নিয়ন্ত্রণ করতে পারেন। উদাহরণস্বরূপ, আমার সংকলকটির typeidজন্য ব্যবহার করা long long"এক্স" দেয়।


10

সি ++ এ, আমাদের ডিক্লাইপ হয়েছে। ডেকলিটাইপ ব্যবহার করে সঠিক ধরণের ভেরিয়েবল প্রদর্শন করার জন্য স্ট্যান্ডার্ড সি ++ তে কোনও উপায় নেই। type_id_with_cvrনীচের মতো প্রিন্ট করতে আমরা বুস্ট টাইপইন্ডেক্স অর্থাত্ (সিভিআর স্ট্যান্ডস কনস্ট, অস্থায়ী, রেফারেন্স) ব্যবহার করতে পারি।

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

using namespace std;
using boost::typeindex::type_id_with_cvr;

int main() {
  int i = 0;
  const int ci = 0;
  cout << "decltype(i) is " << type_id_with_cvr<decltype(i)>().pretty_name() << '\n';
  cout << "decltype((i)) is " << type_id_with_cvr<decltype((i))>().pretty_name() << '\n';
  cout << "decltype(ci) is " << type_id_with_cvr<decltype(ci)>().pretty_name() << '\n';
  cout << "decltype((ci)) is " << type_id_with_cvr<decltype((ci))>().pretty_name() << '\n';
  cout << "decltype(std::move(i)) is " << type_id_with_cvr<decltype(std::move(i))>().pretty_name() << '\n';
  cout << "decltype(std::static_cast<int&&>(i)) is " << type_id_with_cvr<decltype(static_cast<int&&>(i))>().pretty_name() << '\n';
  return 0;
}

1
কোনও সহায়ক ফাংশনটি ব্যবহার করা কি সহজ হবে:template<typename T> void print_type(T){cout << "type T is: "<< type_id_with_cvr<T>().pretty_name()<< '\n';}
r0ng

6

আপনি টাইপটির নামটি কমিয়ে আনতে অপশন-টি (টাইপ) দিয়ে সি ++ ফিল্টও ব্যবহার করতে পারেন:

#include <iostream>
#include <typeinfo>
#include <string>

using namespace std;

int main() {
  auto x = 1;
  string my_type = typeid(x).name();
  system(("echo " + my_type + " | c++filt -t").c_str());
  return 0;
}

শুধুমাত্র লিনাক্সের উপর পরীক্ষিত।


1
জাহান্নাম কুৎসিত তবে আমার যা প্রয়োজন তা করবে। এবং অন্যান্য সমাধানের তুলনায় অনেক ছোট। ম্যাক বিটিডব্লিউতে কাজ করে।
মার্কো লুগলিও

6

হাওয়ার্ড হিন্যান্ট টাইপ নামটি বের করতে ম্যাজিক নম্বর ব্যবহার করেছিলেন 康 桓 string স্ট্রিং উপসর্গ এবং প্রত্যয় প্রস্তাবিত। তবে উপসর্গ / প্রত্যয়টি পরিবর্তন হতে থাকে। "প্রোব_প্রকার" টাইপ_নামের সাহায্যে টাইপটির নাম বের করতে "প্রোব_ টাইপ" এর জন্য স্বয়ংক্রিয়ভাবে উপসর্গ এবং প্রত্যয় মাপ গণনা করা হয়:

#include <iostream>
#include <string_view>

using namespace std;

class probe_type;

template <typename T>
constexpr string_view type_name() {
  string_view probe_type_name("class probe_type");
  const string_view class_specifier("class");

  string_view name;
#ifdef __clang__
  name = __PRETTY_FUNCTION__;
  probe_type_name.remove_prefix(class_specifier.length());
#elif defined(__GNUC__)
  name = __PRETTY_FUNCTION__;
  probe_type_name.remove_prefix(class_specifier.length());
#elif defined(_MSC_VER)
  name = __FUNCSIG__;
#endif

  if (name.find(probe_type_name) != string_view::npos)
    return name;

  const string_view probe_type_raw_name = type_name<probe_type>();

  const size_t prefix_size = probe_type_raw_name.find(probe_type_name);

  name.remove_prefix(prefix_size);
  name.remove_suffix(probe_type_raw_name.length() - prefix_size - probe_type_name.length());

  return name;
}

class test;

int main() {
  cout << type_name<test>() << endl;

  cout << type_name<const int*&>() << endl;
  cout << type_name<unsigned int>() << endl;

  const int ic = 42;
  const int* pic = &ic;
  const int*& rpic = pic;
  cout << type_name<decltype(ic)>() << endl;
  cout << type_name<decltype(pic)>() << endl;
  cout << type_name<decltype(rpic)>() << endl;

  cout << type_name<probe_type>() << endl;
}

আউটপুট

জিসিসি 10.0.0 20190919 ওয়ানডবক্স:

 test
 const int *&
 unsigned int
 const int
 const int *
 const int *&
 constexpr std::string_view type_name() [with T = probe_type; std::string_view = std::basic_string_view<char>]

ঝনঝন 10.0.0 ওয়ান্ডবক্স:

 test
 const int *&
 unsigned int
 const int
 const int *
 const int *&
 std::__1::string_view type_name() [T = probe_type]

ভিএস 2019 সংস্করণ 16.3.3:

class test
const int*&
unsigned int
const int
const int*
const int*&
class std::basic_string_view<char,struct std::char_traits<char> > __cdecl type_name<class probe_type>(void)

5

আরটিটিআই (টাইপড) এর সাথে জড়িত অন্যান্য উত্তর সম্ভবত আপনি যা চান তা হ'ল:

  • আপনি মেমরি ওভারহেড বহন করতে পারেন (যা কিছু সংকলক দিয়ে বিবেচনাযোগ্য হতে পারে)
  • আপনার সংকলকটির বর্গের নামগুলি কার্যকর useful

বিকল্প, (গ্রেগ হিউগিলের উত্তরের অনুরূপ), বৈশিষ্ট্যগুলির একটি সংকলন-সময় সারণী তৈরি করা।

template <typename T> struct type_as_string;

// declare your Wibble type (probably with definition of Wibble)
template <>
struct type_as_string<Wibble>
{
    static const char* const value = "Wibble";
};

সচেতন হন যে আপনি যদি ম্যাক্রোতে ঘোষণাগুলি মুড়ে ফেলে থাকেন, কমা হিসাবে আপনি টেমপ্লেট প্রকারের একাধিক প্যারামিটার (যেমন স্টাড :: ম্যাপ) নেওয়ার জন্য নাম ঘোরাতে সমস্যা হবে have

ভেরিয়েবলের ধরণের নাম অ্যাক্সেস করতে আপনার যা প্রয়োজন তা হল

template <typename T>
const char* get_type_as_string(const T&)
{
    return type_as_string<T>::value;
}

1
কমা সম্পর্কে ভাল বক্তব্য, আমি জানতাম যে ম্যাক্রোগুলি একটি খারাপ ধারণা হবার একটি কারণ ছিল কিন্তু সে সময়টি এটি ভাবেনি!
গ্রেগ হিউগিল

2
স্ট্যাটিক কনস্ট চর * মান = "উইবল"; আপনি সেই
সাথীটি

5

আমার আগেরটির চেয়ে ফাংশন ওভারলোডিং ছাড়াই আরও জেনেরিক সমাধান:

template<typename T>
std::string TypeOf(T){
    std::string Type="unknown";
    if(std::is_same<T,int>::value) Type="int";
    if(std::is_same<T,std::string>::value) Type="String";
    if(std::is_same<T,MyClass>::value) Type="MyClass";

    return Type;}

এখানে মাইক্লাসটি ব্যবহারকারী সংজ্ঞায়িত শ্রেণি। এখানে আরও শর্ত যুক্ত করা যেতে পারে।

উদাহরণ:

#include <iostream>



class MyClass{};


template<typename T>
std::string TypeOf(T){
    std::string Type="unknown";
    if(std::is_same<T,int>::value) Type="int";
    if(std::is_same<T,std::string>::value) Type="String";
    if(std::is_same<T,MyClass>::value) Type="MyClass";
    return Type;}


int main(){;
    int a=0;
    std::string s="";
    MyClass my;
    std::cout<<TypeOf(a)<<std::endl;
    std::cout<<TypeOf(s)<<std::endl;
    std::cout<<TypeOf(my)<<std::endl;

    return 0;}

আউটপুট:

int
String
MyClass

5

আমি নিকের পদ্ধতিটি পছন্দ করি, একটি সম্পূর্ণ ফর্মটি এটি হতে পারে (সমস্ত মৌলিক ডেটা ধরণের জন্য):

template <typename T> const char* typeof(T&) { return "unknown"; }    // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(short&) { return "short"; }
template<> const char* typeof(long&) { return "long"; }
template<> const char* typeof(unsigned&) { return "unsigned"; }
template<> const char* typeof(unsigned short&) { return "unsigned short"; }
template<> const char* typeof(unsigned long&) { return "unsigned long"; }
template<> const char* typeof(float&) { return "float"; }
template<> const char* typeof(double&) { return "double"; }
template<> const char* typeof(long double&) { return "long double"; }
template<> const char* typeof(std::string&) { return "String"; }
template<> const char* typeof(char&) { return "char"; }
template<> const char* typeof(signed char&) { return "signed char"; }
template<> const char* typeof(unsigned char&) { return "unsigned char"; }
template<> const char* typeof(char*&) { return "char*"; }
template<> const char* typeof(signed char*&) { return "signed char*"; }
template<> const char* typeof(unsigned char*&) { return "unsigned char*"; }

2
(i) এটি অন্যান্য ধরণের জন্য কাজ করবে না (অর্থাত্ জেনেরিক নয়); (ii) অকেজো কোড ফোলা; (iii) একই (সঠিকভাবে) এর সাথে typeidবা এর মাধ্যমেও করা যেতে পারে decltype
এডিএমজেড

2
আপনি ঠিক বলেছেন, তবে এটি সমস্ত প্রাথমিক ধরণের জুড়ে ... এবং আমার এখনই এটি দরকার ...
জাহিদ

2
আপনি কি আমাকে বলতে পারবেন, আপনি কীভাবে ডিক্লাইপ দিয়ে এটি করবেন
জাহিদ

1
যদি এটি একটি সংকলন-সময় পরীক্ষা হয়, আপনি এসডিডি :: is_same <T, S> এবং টি এবং এস পেতে ডিক্লাইপ ব্যবহার করতে পারেন
edmz

4

আমি চ্যালেঞ্জ হিসাবে আমি পরীক্ষা করার সিদ্ধান্ত নিয়েছি যে কেউ প্ল্যাটফর্ম-স্বতন্ত্র (আশা) টেম্পলেট কৌশলগুলির সাথে কতদূর যেতে পারে।

সংকলনের সময় নামগুলি সম্পূর্ণ একত্রিত হয় are (যার অর্থtypeid(T).name() ব্যবহার করা যায়নি, সুতরাং আপনাকে স্পষ্টভাবে চক্রবিহীন প্রকারের জন্য নাম সরবরাহ করতে হবে Otherwise অন্যথায় পরিবর্তে স্থানধারীরা প্রদর্শিত হবে))

ব্যবহারের উদাহরণ:

TYPE_NAME(int)
TYPE_NAME(void)
// You probably should list all primitive types here.

TYPE_NAME(std::string)

int main()
{
    // A simple case
    std::cout << type_name<void(*)(int)> << '\n';
    // -> `void (*)(int)`

    // Ugly mess case
    // Note that compiler removes cv-qualifiers from parameters and replaces arrays with pointers.
    std::cout << type_name<void (std::string::*(int[3],const int, void (*)(std::string)))(volatile int*const*)> << '\n';
    // -> `void (std::string::*(int *,int,void (*)(std::string)))(volatile int *const*)`

    // A case with undefined types
    //  If a type wasn't TYPE_NAME'd, it's replaced by a placeholder, one of `class?`, `union?`, `enum?` or `??`.
    std::cout << type_name<std::ostream (*)(int, short)> << '\n';
    // -> `class? (*)(int,??)`
    // With appropriate TYPE_NAME's, the output would be `std::string (*)(int,short)`.
}

কোড:

#include <type_traits>
#include <utility>

static constexpr std::size_t max_str_lit_len = 256;

template <std::size_t I, std::size_t N> constexpr char sl_at(const char (&str)[N])
{
    if constexpr(I < N)
        return str[I];
    else
        return '\0';
}

constexpr std::size_t sl_len(const char *str)
{
    for (std::size_t i = 0; i < max_str_lit_len; i++)
        if (str[i] == '\0')
            return i;
    return 0;
}

template <char ...C> struct str_lit
{
    static constexpr char value[] {C..., '\0'};
    static constexpr int size = sl_len(value);

    template <typename F, typename ...P> struct concat_impl {using type = typename concat_impl<F>::type::template concat_impl<P...>::type;};
    template <char ...CC> struct concat_impl<str_lit<CC...>> {using type = str_lit<C..., CC...>;};
    template <typename ...P> using concat = typename concat_impl<P...>::type;
};

template <typename, const char *> struct trim_str_lit_impl;
template <std::size_t ...I, const char *S> struct trim_str_lit_impl<std::index_sequence<I...>, S>
{
    using type = str_lit<S[I]...>;
};
template <std::size_t N, const char *S> using trim_str_lit = typename trim_str_lit_impl<std::make_index_sequence<N>, S>::type;

#define STR_LIT(str) ::trim_str_lit<::sl_len(str), ::str_lit<STR_TO_VA(str)>::value>
#define STR_TO_VA(str) STR_TO_VA_16(str,0),STR_TO_VA_16(str,16),STR_TO_VA_16(str,32),STR_TO_VA_16(str,48)
#define STR_TO_VA_16(str,off) STR_TO_VA_4(str,0+off),STR_TO_VA_4(str,4+off),STR_TO_VA_4(str,8+off),STR_TO_VA_4(str,12+off)
#define STR_TO_VA_4(str,off) ::sl_at<off+0>(str),::sl_at<off+1>(str),::sl_at<off+2>(str),::sl_at<off+3>(str)

template <char ...C> constexpr str_lit<C...> make_str_lit(str_lit<C...>) {return {};}
template <std::size_t N> constexpr auto make_str_lit(const char (&str)[N])
{
    return trim_str_lit<sl_len((const char (&)[N])str), str>{};
}

template <std::size_t A, std::size_t B> struct cexpr_pow {static constexpr std::size_t value = A * cexpr_pow<A,B-1>::value;};
template <std::size_t A> struct cexpr_pow<A,0> {static constexpr std::size_t value = 1;};
template <std::size_t N, std::size_t X, typename = std::make_index_sequence<X>> struct num_to_str_lit_impl;
template <std::size_t N, std::size_t X, std::size_t ...Seq> struct num_to_str_lit_impl<N, X, std::index_sequence<Seq...>>
{
    static constexpr auto func()
    {
        if constexpr (N >= cexpr_pow<10,X>::value)
            return num_to_str_lit_impl<N, X+1>::func();
        else
            return str_lit<(N / cexpr_pow<10,X-1-Seq>::value % 10 + '0')...>{};
    }
};
template <std::size_t N> using num_to_str_lit = decltype(num_to_str_lit_impl<N,1>::func());


using spa = str_lit<' '>;
using lpa = str_lit<'('>;
using rpa = str_lit<')'>;
using lbr = str_lit<'['>;
using rbr = str_lit<']'>;
using ast = str_lit<'*'>;
using amp = str_lit<'&'>;
using con = str_lit<'c','o','n','s','t'>;
using vol = str_lit<'v','o','l','a','t','i','l','e'>;
using con_vol = con::concat<spa, vol>;
using nsp = str_lit<':',':'>;
using com = str_lit<','>;
using unk = str_lit<'?','?'>;

using c_cla = str_lit<'c','l','a','s','s','?'>;
using c_uni = str_lit<'u','n','i','o','n','?'>;
using c_enu = str_lit<'e','n','u','m','?'>;

template <typename T> inline constexpr bool ptr_or_ref = std::is_pointer_v<T> || std::is_reference_v<T> || std::is_member_pointer_v<T>;
template <typename T> inline constexpr bool func_or_arr = std::is_function_v<T> || std::is_array_v<T>;

template <typename T> struct primitive_type_name {using value = unk;};

template <typename T, typename = std::enable_if_t<std::is_class_v<T>>> using enable_if_class = T;
template <typename T, typename = std::enable_if_t<std::is_union_v<T>>> using enable_if_union = T;
template <typename T, typename = std::enable_if_t<std::is_enum_v <T>>> using enable_if_enum  = T;
template <typename T> struct primitive_type_name<enable_if_class<T>> {using value = c_cla;};
template <typename T> struct primitive_type_name<enable_if_union<T>> {using value = c_uni;};
template <typename T> struct primitive_type_name<enable_if_enum <T>> {using value = c_enu;};

template <typename T> struct type_name_impl;

template <typename T> using type_name_lit = std::conditional_t<std::is_same_v<typename primitive_type_name<T>::value::template concat<spa>,
                                                                               typename type_name_impl<T>::l::template concat<typename type_name_impl<T>::r>>,
                                            typename primitive_type_name<T>::value,
                                            typename type_name_impl<T>::l::template concat<typename type_name_impl<T>::r>>;
template <typename T> inline constexpr const char *type_name = type_name_lit<T>::value;

template <typename T, typename = std::enable_if_t<!std::is_const_v<T> && !std::is_volatile_v<T>>> using enable_if_no_cv = T;

template <typename T> struct type_name_impl
{
    using l = typename primitive_type_name<T>::value::template concat<spa>;
    using r = str_lit<>;
};
template <typename T> struct type_name_impl<const T>
{
    using new_T_l = std::conditional_t<type_name_impl<T>::l::size && !ptr_or_ref<T>,
                                       spa::concat<typename type_name_impl<T>::l>,
                                       typename type_name_impl<T>::l>;
    using l = std::conditional_t<ptr_or_ref<T>,
                                 typename new_T_l::template concat<con>,
                                 con::concat<new_T_l>>;
    using r = typename type_name_impl<T>::r;
};
template <typename T> struct type_name_impl<volatile T>
{
    using new_T_l = std::conditional_t<type_name_impl<T>::l::size && !ptr_or_ref<T>,
                                       spa::concat<typename type_name_impl<T>::l>,
                                       typename type_name_impl<T>::l>;
    using l = std::conditional_t<ptr_or_ref<T>,
                                 typename new_T_l::template concat<vol>,
                                 vol::concat<new_T_l>>;
    using r = typename type_name_impl<T>::r;
};
template <typename T> struct type_name_impl<const volatile T>
{
    using new_T_l = std::conditional_t<type_name_impl<T>::l::size && !ptr_or_ref<T>,
                                       spa::concat<typename type_name_impl<T>::l>,
                                       typename type_name_impl<T>::l>;
    using l = std::conditional_t<ptr_or_ref<T>,
                                 typename new_T_l::template concat<con_vol>,
                                 con_vol::concat<new_T_l>>;
    using r = typename type_name_impl<T>::r;
};
template <typename T> struct type_name_impl<T *>
{
    using l = std::conditional_t<func_or_arr<T>,
                                 typename type_name_impl<T>::l::template concat<lpa, ast>,
                                 typename type_name_impl<T>::l::template concat<     ast>>;
    using r = std::conditional_t<func_or_arr<T>,
                                 rpa::concat<typename type_name_impl<T>::r>,
                                             typename type_name_impl<T>::r>;
};
template <typename T> struct type_name_impl<T &>
{
    using l = std::conditional_t<func_or_arr<T>,
                                 typename type_name_impl<T>::l::template concat<lpa, amp>,
                                 typename type_name_impl<T>::l::template concat<     amp>>;
    using r = std::conditional_t<func_or_arr<T>,
                                 rpa::concat<typename type_name_impl<T>::r>,
                                             typename type_name_impl<T>::r>;
};
template <typename T> struct type_name_impl<T &&>
{
    using l = std::conditional_t<func_or_arr<T>,
                                 typename type_name_impl<T>::l::template concat<lpa, amp, amp>,
                                 typename type_name_impl<T>::l::template concat<     amp, amp>>;
    using r = std::conditional_t<func_or_arr<T>,
                                 rpa::concat<typename type_name_impl<T>::r>,
                                             typename type_name_impl<T>::r>;
};
template <typename T, typename C> struct type_name_impl<T C::*>
{
    using l = std::conditional_t<func_or_arr<T>,
                                 typename type_name_impl<T>::l::template concat<lpa, type_name_lit<C>, nsp, ast>,
                                 typename type_name_impl<T>::l::template concat<     type_name_lit<C>, nsp, ast>>;
    using r = std::conditional_t<func_or_arr<T>,
                                 rpa::concat<typename type_name_impl<T>::r>,
                                             typename type_name_impl<T>::r>;
};
template <typename T> struct type_name_impl<enable_if_no_cv<T[]>>
{
    using l = typename type_name_impl<T>::l;
    using r = lbr::concat<rbr, typename type_name_impl<T>::r>;
};
template <typename T, std::size_t N> struct type_name_impl<enable_if_no_cv<T[N]>>
{
    using l = typename type_name_impl<T>::l;
    using r = lbr::concat<num_to_str_lit<N>, rbr, typename type_name_impl<T>::r>;
};
template <typename T> struct type_name_impl<T()>
{
    using l = typename type_name_impl<T>::l;
    using r = lpa::concat<rpa, typename type_name_impl<T>::r>;
};
template <typename T, typename P1, typename ...P> struct type_name_impl<T(P1, P...)>
{
    using l = typename type_name_impl<T>::l;
    using r = lpa::concat<type_name_lit<P1>,
                          com::concat<type_name_lit<P>>..., rpa, typename type_name_impl<T>::r>;
};

#define TYPE_NAME(t) template <> struct primitive_type_name<t> {using value = STR_LIT(#t);};

2
#include <iostream>
#include <typeinfo>
using namespace std;
#define show_type_name(_t) \
    system(("echo " + string(typeid(_t).name()) + " | c++filt -t").c_str())

int main() {
    auto a = {"one", "two", "three"};
    cout << "Type of a: " << typeid(a).name() << endl;
    cout << "Real type of a:\n";
    show_type_name(a);
    for (auto s : a) {
        if (string(s) == "one") {
            cout << "Type of s: " << typeid(s).name() << endl;
            cout << "Real type of s:\n";
            show_type_name(s);
        }
        cout << s << endl;
    }

    int i = 5;
    cout << "Type of i: " << typeid(i).name() << endl;
    cout << "Real type of i:\n";
    show_type_name(i);
    return 0;
}

আউটপুট:

Type of a: St16initializer_listIPKcE
Real type of a:
std::initializer_list<char const*>
Type of s: PKc
Real type of s:
char const*
one
two
three
Type of i: i
Real type of i:
int

2

কার্যকর আধুনিক সি ++ এ স্কট মায়ার্স দ্বারা ব্যাখ্যা করা হিসাবে,

কলগুলি যে std::type_info::nameকোনও বুদ্ধিমানের ফেরতের গ্যারান্টিযুক্ত নয়।

সর্বোত্তম সমাধান হ'ল সংকলকটি টাইপ ছাড়ের সময় একটি ত্রুটি বার্তা উত্পন্ন করতে দেয়, উদাহরণস্বরূপ,

template<typename T>
class TD;

int main(){
    const int theAnswer = 32;
    auto x = theAnswer;
    auto y = &theAnswer;
    TD<decltype(x)> xType;
    TD<decltype(y)> yType;
    return 0;
}

সংকলকগুলির উপর নির্ভর করে ফলাফলটি এরকম কিছু হবে,

test4.cpp:10:21: error: aggregate TD<int> xType has incomplete type and cannot be defined TD<decltype(x)> xType;

test4.cpp:11:21: error: aggregate TD<const int *> yType has incomplete type and cannot be defined TD<decltype(y)> yType;

সুতরাং, আমরা জানতে পারি যে xএর ধরণ int, yএর প্রকারconst int*


0

যে কারও জন্য এখনও দেখা হচ্ছে, আমি সম্প্রতি একই সমস্যা পেয়েছি এবং এই পোস্টের উত্তরগুলির ভিত্তিতে একটি ছোট গ্রন্থাগার লেখার সিদ্ধান্ত নিয়েছি। এটি কনটেক্সপ্রিপ প্রকারের নাম সরবরাহ করে এবং টাইপ সূচকগুলি ম্যাক, উইন্ডোজ এবং উবুন্টুতে পরীক্ষা করা হয়।

লাইব্রেরির কোডটি এখানে: https://github.com/TheLartians/StaticTypeInfo

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.