সুবিধামত সি ++ তে কমপাইল-টাইম স্ট্রিংস ঘোষণা করা


137

সি ++ এ সংকলনকালে স্ট্রিংগুলি তৈরি এবং পরিচালনা করতে সক্ষম হওয়ায় বেশ কয়েকটি দরকারী অ্যাপ্লিকেশন রয়েছে। যদিও সি ++ তে কম্পাইল-টাইম স্ট্রিংগুলি তৈরি করা সম্ভব, প্রক্রিয়াটি খুব জটিল, কারণ স্ট্রিংটিকে অক্ষরের বিচিত্র ক্রমিক হিসাবে ঘোষণা করা দরকার, যেমন

using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;

স্ট্রিং কনটেনটেশন, স্ট্রারিং এক্সট্রাকশন এবং আরও অনেকের মতো অপারেশনগুলি অক্ষরের অনুক্রমের ক্রিয়াকলাপ হিসাবে সহজেই প্রয়োগ করা যেতে পারে। কম্পাইল-টাইম স্ট্রিংগুলি আরও সুবিধাজনকভাবে ঘোষণা করা সম্ভব? যদি তা না হয় তবে কী এমন কোনও প্রস্তাব রয়েছে যা সংকলন-সময়ের স্ট্রিংগুলির সুবিধাজনক ঘোষণার অনুমতি দেবে?

বিদ্যমান পদ্ধতির ব্যর্থতা কেন

আদর্শভাবে, আমরা নিম্নরূপে সংকলন-সময়ের স্ট্রিংগুলি ঘোষণা করতে সক্ষম হতে চাই:

// Approach 1
using str1 = sequence<"Hello, world!">;

বা, ব্যবহারকারী-সংজ্ঞায়িত আক্ষরিক ব্যবহার করে,

// Approach 2
constexpr auto str2 = "Hello, world!"_s;

যেখানে decltype(str2)একজন constexprকনস্ট্রাক্টর থাকবে পদ্ধতির 1 এর একটি ম্যাসেয়ার সংস্করণ বাস্তবায়ন করা সম্ভব, আপনি নিম্নলিখিতটি করতে পারেন তার সুযোগ নিয়ে:

template <unsigned Size, const char Array[Size]>
struct foo;

যাইহোক, অ্যারের বাহ্যিক সংযোগ থাকা দরকার, সুতরাং কাজ করার জন্য 1 পদ্ধতির পেতে আমাদের এই জাতীয় কিছু লিখতে হবে:

/* Implementation of array to sequence goes here. */

constexpr const char str[] = "Hello, world!";

int main()
{
    using s = string<13, str>;
    return 0;
}

বলা বাহুল্য, এটি খুব অসুবিধাজনক। অ্যাপ্রোচ 2 বাস্তবায়ন সম্ভব নয়। যদি আমরা কোনও ( constexpr) আক্ষরিক অপারেটর ঘোষণা করতে পারি, তবে আমরা কীভাবে রিটার্নের ধরণটি নির্দিষ্ট করব? যেহেতু অক্ষরের একটি বৈচিত্র্যক্রমিক ক্রমটি ফেরত দেওয়ার জন্য আমাদের অপারেটরটির প্রয়োজন, তাই আমাদের রিটার্নের ধরণটি const char*নির্দিষ্ট করতে প্যারামিটারটি ব্যবহার করতে হবে:

constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */

এটি একটি সংকলন ত্রুটির ফলস্বরূপ, কারণ sএটি নয় constexpr। নিম্নলিখিতটি ব্যবহার করে এটিকে ঘিরে কাজ করার চেষ্টা করা খুব বেশি সহায়ক হয় না।

template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }

মান নির্দেশ করে যে এই নির্দিষ্ট আক্ষরিক অপারেটর ফর্মটি পূর্ণসংখ্যা এবং ভাসমান-পয়েন্ট ধরণের জন্য সংরক্ষিত। যদিও 123_sকাজ করবে, abc_sহবে না। যদি আমরা সম্পূর্ণরূপে ব্যবহারকারী-সংজ্ঞায়িত আক্ষরিক খাঁজ করি এবং কেবল একটি নিয়মিত constexprফাংশন ব্যবহার করি ?

template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */

আগের মতোই, আমরা এই সমস্যাটি নিয়ে চলেছি যে অ্যারে, এখন constexprফাংশনটির পরামিতি , নিজেই আর কোনও constexprধরণের নয়।

আমি বিশ্বাস করি যে একটি সি প্রিপ্রসেসর ম্যাক্রো সংজ্ঞায়িত করা সম্ভব হবে যা স্ট্রিং এবং স্ট্রিংয়ের BOOST_PP_FORআকারটিকে আর্গুমেন্ট হিসাবে গ্রহণ করে এবং স্ট্রিংয়ের অক্ষরগুলির সমন্বয়ে একটি ক্রম প্রদান করে ( স্ট্রিংকরণ, অ্যারে সাবস্ক্রিপ্ট এবং এর মতো)। তবে এ জাতীয় ম্যাক্রো প্রয়োগের জন্য আমার কাছে সময় (বা পর্যাপ্ত আগ্রহ) নেই =)


2
বুস্টের একটি ম্যাক্রো রয়েছে যা একটি স্ট্রিং সংজ্ঞায়িত করে যা ধ্রুবক অভিব্যক্তি হিসাবে ব্যবহার করা যেতে পারে। ভাল, এটি একটি শ্রেণীর সংজ্ঞা দেয় যার স্ট্রিং সদস্য রয়েছে। আপনি কি এটি পরীক্ষা করে দেখেছেন?
পাব্বি


1
স্ট্যাক ওভারফ্লো কোনও কিছুর প্রস্তাব রয়েছে কিনা তা জিজ্ঞাসা করার উপযুক্ত জায়গা নয়। এর জন্য সেরা জায়গাটি হবে সি ++ সাইট
নিকল বোলাস

1
মূলত, আপনি অ্যারে / পিটিআর তে সঞ্চিত অক্ষরগুলিকে প্যারামিটার প্যাকটিতে প্রসারিত করেন (যেমন জিয়ো করেছেন)। যদিও এগুলি নন-টাইপ টেম্পলেট আর্গুমেন্টে বিভক্ত নয়, আপনি এগুলি constexprফাংশনগুলির মধ্যে ব্যবহার করতে পারেন এবং অ্যারেগুলি (আরম্ভ করে, কনক্যাট, সাবস্ট্রাস্ট ইত্যাদি) শুরু করতে পারেন।
ডায়াপ 11:25

1
@MareInfinitus সংক্ষেপে, সংকলনকালে constexprস্ট্রিংগুলি বিশ্লেষণ করা যায়, যাতে আপনি ফলাফলের উপর নির্ভর করে বিভিন্ন কোড পাথ নিতে পারেন। মূলত, আপনি সি ++ এর মধ্যে ইডিএল তৈরি করতে পারেন; অ্যাপ্লিকেশনগুলি বেশ সীমাহীন।
অকার্যকর-নির্দেশক

উত্তর:


127

সি ++ নাও ২০১২- তে উপস্থাপিত স্কট শুরারstr_const কমনীয়তার সাথে মেলে আমি কিছু দেখিনি । যদিও এটি প্রয়োজন ।constexpr

আপনি এটি কীভাবে ব্যবহার করতে পারেন এবং এটি কী করতে পারে তা এখানে রয়েছে:

int
main()
{
    constexpr str_const my_string = "Hello, world!";
    static_assert(my_string.size() == 13, "");
    static_assert(my_string[4] == 'o', "");
    constexpr str_const my_other_string = my_string;
    static_assert(my_string == my_other_string, "");
    constexpr str_const world(my_string, 7, 5);
    static_assert(world == "world", "");
//  constexpr char x = world[5]; // Does not compile because index is out of range!
}

এটি কমপাইল-টাইম রেঞ্জ চেকিংয়ের চেয়ে বেশি শীতল হয় না!

ব্যবহার এবং বাস্তবায়ন উভয়ই ম্যাক্রো থেকে মুক্ত। এবং স্ট্রিং আকারে কোনও কৃত্রিম সীমা নেই। আমি বাস্তবায়নটি এখানে পোস্ট করব, তবে আমি স্কটের অন্তর্নিহিত কপিরাইটকে সম্মান করছি। বাস্তবায়ন উপরের সাথে যুক্ত তার উপস্থাপনার একক স্লাইডে রয়েছে।


3
নতুন কনস্টেক্সপ্রিং স্ট্রিং তৈরি করা অপারেশনগুলি (স্ট্রিং কনটেনটেশন এবং সাবস্ট্রিং এক্সট্রাকশন এর মতো) এই পদ্ধতির সাথে কী কাজ করতে পারে? সম্ভবত দুটি কনস্টেক্সপ্রিং-স্ট্রিং ক্লাস ব্যবহার করা হচ্ছে (একটি উপর ভিত্তি করে str_constঅন্যটি ভিত্তিক অন্য sequence), এটি সম্ভব হতে পারে possible ব্যবহারকারীর str_constস্ট্রিংটি আরম্ভ করতে ব্যবহার করা হত , তবে পরবর্তী ক্রিয়াকলাপগুলি যে নতুন স্ট্রিং তৈরি করে তা প্রত্যাবর্তন sequenceকরে।
অকার্যকর-নির্দেশক

5
এটি কোডের একটি ভাল অংশ। যাইহোক, এই পদ্ধতির টেমপ্লেট পরামিতি হিসাবে অক্ষর অনুসারে ঘোষণা করা স্ট্রিংয়ের সাথে তুলনা করে এখনও একটি ত্রুটি রয়েছে: একটি str_const একটি ধ্রুবক মান এবং কোনও প্রকার নয়, এইভাবে প্রচুর রূপক আইডিয়ামগুলির ব্যবহারকে প্রতিরোধ করে।
জিন-বার্নার্ড জানসেন

1
@ জেবি জ্যানসেন, হ্যাশ ফাংশন ছাড়াই কোনও ধরণের স্ট্রিং সংকলন করা সম্ভব যা পরে টেমপ্লেট প্যারামিটার হিসাবে ব্যবহার করা যেতে পারে। প্রতিটি ভিন্ন স্ট্রিং একটি ভিন্ন ধরণের দেয়। মূল ধারণাটি হ'ল স্ট্রিংটিকে একটি অক্ষর প্যাকে পরিণত করা template<char... cs>। তত্ত্বগতভাবে, আপনি এমন কিছু তৈরি করতে পারেন যা আক্ষরিক স্ট্রিং নেয় এবং সামগ্রীগুলিকে কোনও ফাংশনে সংকলিত করে। উত্তরটি ডাইপ দিয়ে দেখুন। একটি খুব সম্পূর্ণ দেখা গ্রন্থাগার রূপান্তর হয় । মূলত, আপনি যেকোন ম্যাপিংকে আক্ষরিক স্ট্রিং থেকে প্রকারভেদে সংজ্ঞায়িত করতে পারেন এবং এ জাতীয় প্রযুক্তির মাধ্যমে এটি বাস্তবায়ন করতে পারেন।
অ্যারন ম্যাকডেইড

1
আমি উদ্যম ভাগ করি না ... টেমপ্লেট metafunctions সাথে কাজ করে না - খুব নিরীহ আপস যে constexpr ফাংশন রানটাইম এ callable হইবে কারণ বিরক্তিকর - কোন সত্য সংযুক্তকরণের, একটি গৃহস্থালি অ্যারে (হেডারের মধ্যে কুশ্রী) এর সংজ্ঞা প্রয়োজন - এই যদিও পূর্বোক্ত কনস্টেক্সপ্রস আপোসিকে ধন্যবাদ জানায় বেশিরভাগ ম্যাক্রোলেস সমাধানের ক্ষেত্রে সত্য - এবং সীমার চেকিং আমাকে খুব বেশি প্রভাবিত করে না কারণ এমনকি স্বল্পতম কনস্টেক্সারপ কনস্টেক্স চার * এরও এটি রয়েছে। আমি আমার নিজস্ব প্যারামিটার প্যাক স্ট্রিংটি ঘূর্ণিত করেছি, যা অ্যারে সংজ্ঞা ব্যয়ে আক্ষরিক (একটি মেটাফিউশন ব্যবহার করে) তৈরিও করা যেতে পারে।
অর্ণ ভোগেল

2
@ ব্যবহারকারী 975326: আমি এটির বাস্তবায়নটি আমার কেবল পর্যালোচনা করেছি এবং দেখে মনে হচ্ছে আমি একটি যুক্ত করেছি constexpr operator==। দুঃখিত। স্কটের উপস্থাপনাটি আপনাকে এটি কীভাবে শুরু করতে হবে তা শুরু করা উচিত। এটি সি ++ 11 এর তুলনায় সি ++ 14 এ অনেক সহজ। আমি সি ++ 11 এ চেষ্টা করেও বিরক্ত করব না। স্কট এর সর্বশেষ constexprআলোচনা এখানে দেখুন: youtube.com/user/CppCon
হাওয়ার্ড Hinnant

41

আমি বিশ্বাস করি যে একটি সি প্রিপ্রসেসর ম্যাক্রো সংজ্ঞায়িত করা সম্ভব হবে যা স্ট্রিং এবং স্ট্রিংয়ের আকারটি আর্গুমেন্ট হিসাবে গ্রহণ করে এবং স্ট্রিংয়ের অক্ষরগুলির সমন্বয়যুক্ত একটি ক্রম ফেরত দেয় (BOOST_PP_FOR, স্ট্রিংফিকেশন, অ্যারে সাবস্ক্রিপ্ট এবং এর মতো) using তবে এ জাতীয় ম্যাক্রো বাস্তবায়নের জন্য আমার কাছে সময় (বা পর্যাপ্ত আগ্রহ) নেই

খুব সহজ ম্যাক্রো এবং কিছু সি ++ 11 বৈশিষ্ট্য ব্যবহার করে বুস্টের উপর নির্ভর না করে এটি বাস্তবায়ন করা সম্ভব:

  1. ল্যাম্বডাস ভেরিয়্যাডিক
  2. টেমপ্লেট
  3. সাধারণীকরণ করা ধ্রুবক অভিব্যক্তি
  4. অ স্থিতিশীল ডেটা সদস্য সূচনা
  5. অভিন্ন সূচনা

(পরের দুটি এখানে কঠোরভাবে প্রয়োজন হয় না)

  1. আমাদের ব্যবহারকারীর দ্বারা 0 টি এন থেকে সরবরাহিত সূচকগুলি সহ একটি বৈকল্পিক টেম্পলেট ইনস্ট্যান্ট করতে সক্ষম হওয়া দরকার - এটি একটি সরঞ্জাম উদাহরণস্বরূপ বৈকল্পিক টেমপ্লেট ফাংশনের যুক্তিতে টুপল প্রসারিত করার জন্যও দরকারী (প্রশ্নগুলি দেখুন: আমি কীভাবে বৈকল্পিক টেমপ্লেট ফাংশনের যুক্তিতে একটি টুপল প্রসারিত করব?
    " প্যাকেজটি প্যাক করা হচ্ছে না "ম্যাচের ফাংশন পয়েন্টারকে কল করতে একটি টিপল )

    namespace  variadic_toolbox
    {
        template<unsigned  count, 
            template<unsigned...> class  meta_functor, unsigned...  indices>
        struct  apply_range
        {
            typedef  typename apply_range<count-1, meta_functor, count-1, indices...>::result  result;
        };
    
        template<template<unsigned...> class  meta_functor, unsigned...  indices>
        struct  apply_range<0, meta_functor, indices...>
        {
            typedef  typename meta_functor<indices...>::result  result;
        };
    }
  2. তারপরে নন-টাইপ প্যারামিটার চর সহ স্ট্রিং নামক একটি বৈকল্পিক টেম্পলেট সংজ্ঞায়িত করুন:

    namespace  compile_time
    {
        template<char...  str>
        struct  string
        {
            static  constexpr  const char  chars[sizeof...(str)+1] = {str..., '\0'};
        };
    
        template<char...  str>
        constexpr  const char  string<str...>::chars[sizeof...(str)+1];
    }
  3. এখন সবচেয়ে আকর্ষণীয় অংশ - অক্ষর অক্ষরে স্ট্রিং টেম্পলেট মধ্যে পাস:

    namespace  compile_time
    {
        template<typename  lambda_str_type>
        struct  string_builder
        {
            template<unsigned... indices>
            struct  produce
            {
                typedef  string<lambda_str_type{}.chars[indices]...>  result;
            };
        };
    }
    
    #define  CSTRING(string_literal)                                                        \
        []{                                                                                 \
            struct  constexpr_string_type { const char * chars = string_literal; };         \
            return  variadic_toolbox::apply_range<sizeof(string_literal)-1,                 \
                compile_time::string_builder<constexpr_string_type>::produce>::result{};    \
        }()

একটি সাধারণ কনটেন্টেশন বিক্ষোভের ব্যবহারটি দেখায়:

    namespace  compile_time
    {
        template<char...  str0, char...  str1>
        string<str0..., str1...>  operator*(string<str0...>, string<str1...>)
        {
            return  {};
        }
    }

    int main()
    {
        auto  str0 = CSTRING("hello");
        auto  str1 = CSTRING(" world");

        std::cout << "runtime concat: " <<  str_hello.chars  << str_world.chars  << "\n <=> \n";
        std::cout << "compile concat: " <<  (str_hello * str_world).chars  <<  std::endl;
    }

https://ideone.com/8Ft2xu


1
এটি এত সহজ যে আমি এখনও বিশ্বাস করতে পারি না এটি কাজ করে। +1 টি! একটি জিনিস: আপনি স্বাক্ষরবিহীন পরিবর্তে সাইজ_টি ব্যবহার করবেন না?
kirbyfan64sos 21

1
এবং operator+পরিবর্তে ব্যবহার সম্পর্কে কি operator*? (str_hello + str_world)
রেমি লেবেউ

আমি জনপ্রিয় স্কট শুরার আরআর_কনস্ট পদ্ধতির চেয়ে এই সমাধানটিকে অগ্রাধিকার দিই, যেহেতু এই পদ্ধতিটি নিশ্চিত করে যে অন্তর্নিহিত ডেটা কনটেক্সপ্রপযুক্ত। শুরার পদ্ধতিটি আমাকে রান টাইমে একটি চর [] স্ট্যাক ভেরিয়েবলের সাহায্যে একটি স্ট্রিংকোনস্ট তৈরি করতে দেয়; আমি কোনও ফাংশন থেকে নিরাপদে কোনও str_const ফিরিয়ে দিতে বা অন্য থ্রেডে পাস করতে পারি না।
গ্লেন

লিঙ্কটি মারা গেছে ... কেউ কি এটিকে পুনরায় পোস্ট করতে পারে? @ গ্লেন?
einpoklum

আপনার CSTRINGম্যাক্রোতে ল্যাম্বদার চারপাশে আপনার বাড়তি জোড় ধনুর্বন্ধনী যুক্ত করা উচিত । অন্যথায় আপনি CSTRINGকোনও []অপারেটরের কাছে একটি কলটির ভিতরে তৈরি করতে পারবেন না , কারণ [[ডাবলটি গুণাবলীর জন্য সংরক্ষিত।
ফ্লোরস্তান

21

সম্পাদনা করুন: হাওয়ার্ড হিন্যান্ট হিসাবে (এবং আমি কিছুটা ওপিতে আমার মন্তব্যে) উল্লেখ করেছি, আপনার একক টেমপ্লেট যুক্তি হিসাবে স্ট্রিংয়ের প্রতিটি চরিত্রের সাথে কোনও ধরণের প্রয়োজন হবে না। আপনার যদি এটির প্রয়োজন হয় তবে নীচে একটি ম্যাক্রো মুক্ত সমাধান রয়েছে।

সংকলনের সময় স্ট্রিংগুলির সাথে কাজ করার চেষ্টা করার সময় আমি একটি কৌশল পেয়েছি। এটিতে "টেম্পলেট স্ট্রিং" ছাড়াও অন্য ধরণের প্রবর্তন করা দরকার তবে ফাংশনগুলির মধ্যে আপনি এই ধরণের সুযোগ সীমাবদ্ধ করতে পারেন।

এটি ম্যাক্রোগুলি ব্যবহার করে না কিছু সি ++ 11 বৈশিষ্ট্য ব্যবহার করে।

#include <iostream>

// helper function
constexpr unsigned c_strlen( char const* str, unsigned count = 0 )
{
    return ('\0' == str[0]) ? count : c_strlen(str+1, count+1);
}

// helper "function" struct
template < char t_c, char... tt_c >
struct rec_print
{
    static void print()
    {
        std::cout << t_c;
        rec_print < tt_c... > :: print ();
    }
};
    template < char t_c >
    struct rec_print < t_c >
    {
        static void print() { std::cout << t_c; }
    };


// destination "template string" type
template < char... tt_c >
struct exploded_string
{
    static void print()
    {
        rec_print < tt_c... > :: print();
    }
};

// struct to explode a `char const*` to an `exploded_string` type
template < typename T_StrProvider, unsigned t_len, char... tt_c >
struct explode_impl
{
    using result =
        typename explode_impl < T_StrProvider, t_len-1,
                                T_StrProvider::str()[t_len-1],
                                tt_c... > :: result;
};

    template < typename T_StrProvider, char... tt_c >
    struct explode_impl < T_StrProvider, 0, tt_c... >
    {
         using result = exploded_string < tt_c... >;
    };

// syntactical sugar
template < typename T_StrProvider >
using explode =
    typename explode_impl < T_StrProvider,
                            c_strlen(T_StrProvider::str()) > :: result;


int main()
{
    // the trick is to introduce a type which provides the string, rather than
    // storing the string itself
    struct my_str_provider
    {
        constexpr static char const* str() { return "hello world"; }
    };

    auto my_str = explode < my_str_provider >{};    // as a variable
    using My_Str = explode < my_str_provider >;    // as a type

    my_str.print();
}

1
আমি শুধু ব্যয় করেছেন সপ্তাহান্তে স্বাধীনভাবে কোডের একটি অনুরূপ টুকরা উন্নয়নশীল, এবং পার্স টাইপ স্ট্রিং একটি খুব মৌলিক সিস্টেম উপার্জন, যেমন pair<int,pair<char,double>>। আমি নিজেকে গর্বিত করেছিলাম এবং তারপরে এই উত্তরটি আবিষ্কার করেছি এবং আজ রূপক গ্রন্থাগার! এর মতো নির্বোধ প্রকল্পগুলি শুরু করার আগে আমার আরও সত্যই অনুসন্ধান করা উচিত :-) আমার ধারণা, তাত্ত্বিকভাবে, এই ধরণের প্রযুক্তি থেকে সম্পূর্ণ সি ++ সংকলক তৈরি করা যেতে পারে। এটি দিয়ে তৈরি করা ক্রেজিস্ট জিনিসটি কী?
অ্যারন ম্যাকডেইড

আমি জানি না। সত্যিকারের প্রকল্পে আমি কখনই এই কৌশলগুলি ব্যবহার করি নি, তাই আমি এই পদ্ধতির অনুসরণ করি নি। যদিও আমি মনে করি আমি স্থানীয় ধরণের ট্রিকের কিছুটা ভিন্নতা মনে করি যা কিছুটা সুবিধাজনক ছিল .. সম্ভবত কোনও স্থানীয় অচল char[]
dyp

আপনি কি এর my_str.print();পরিবর্তে মানে str.print();?
মাইকে

একটি সি ++ 14 সামান্য সংক্ষিপ্ত সংস্করণ আছে?
মাইকে

আপনার সরবরাহকারী তৈরি করতে হবে এটি লজ্জাজনক (কমপক্ষে সি ++ 11 এ) - আমি সত্যই একই বিবৃতিতে একটি স্ট্রিং ব্যবহার করতে সক্ষম হতে চাই: /
আলেক টিল

10

আপনি যদি বুস্ট সমাধানটি ব্যবহার করতে না চান তবে আপনি সাধারণ ম্যাক্রোগুলি তৈরি করতে পারেন যা অনুরূপ কিছু করবে:

#define MACRO_GET_1(str, i) \
    (sizeof(str) > (i) ? str[(i)] : 0)

#define MACRO_GET_4(str, i) \
    MACRO_GET_1(str, i+0),  \
    MACRO_GET_1(str, i+1),  \
    MACRO_GET_1(str, i+2),  \
    MACRO_GET_1(str, i+3)

#define MACRO_GET_16(str, i) \
    MACRO_GET_4(str, i+0),   \
    MACRO_GET_4(str, i+4),   \
    MACRO_GET_4(str, i+8),   \
    MACRO_GET_4(str, i+12)

#define MACRO_GET_64(str, i) \
    MACRO_GET_16(str, i+0),  \
    MACRO_GET_16(str, i+16), \
    MACRO_GET_16(str, i+32), \
    MACRO_GET_16(str, i+48)

#define MACRO_GET_STR(str) MACRO_GET_64(str, 0), 0 //guard for longer strings

using seq = sequence<MACRO_GET_STR("Hello world!")>;

একমাত্র সমস্যা হ'ল 64 অক্ষরের স্থির আকার (অতিরিক্ত অতিরিক্ত শূন্য)। তবে এটি আপনার প্রয়োজনের উপর নির্ভর করে সহজেই পরিবর্তন করা যেতে পারে।


আমি এই সমাধানটি অনেক পছন্দ করি; এটি খুব সহজ এবং কাজটি মার্জিতভাবে করে। ম্যাক্রোটি সংশোধন করা সম্ভব যাতে কোনও কিছুই সংযুক্ত না হয় sizeof(str) > i(অতিরিক্ত 0,টোকেন যুক্ত করার পরিবর্তে )? কোনও trimমেটাফ্যাঙ্কশনটি সংজ্ঞায়িত করা সহজ যা ম্যাক্রো ডাকা হওয়ার পরে এটি করবে but তবে ম্যাক্রো নিজেই সংশোধন করতে পারলে খুব ভাল।
অকার্যকর-নির্দেশক

অসম্ভব কারণ পার্সার বুঝতে পারেন না sizeof(str)। ম্যানুয়ালি স্ট্রিংয়ের আকার যুক্ত করা এটির পক্ষে সম্ভব তবে এটির MACRO_GET_STR(6, "Hello")জন্য বুস্ট ম্যাক্রোগুলি কাজ করতে পারে কারণ ম্যানুয়ালি এটি লেখার জন্য 100 গুণ বেশি কোডের প্রয়োজন হয় (আপনার মতো সরল জিনিস প্রয়োগ করতে হবে 1+1)।
ইয়ংকস

6

আমি বিশ্বাস করি যে একটি সি প্রিপ্রসেসর ম্যাক্রো সংজ্ঞায়িত করা সম্ভব হবে যা স্ট্রিং এবং স্ট্রিংয়ের আকারটি আর্গুমেন্ট হিসাবে গ্রহণ করে এবং স্ট্রিংয়ের অক্ষরগুলির সমন্বয়ে একটি ক্রম ফেরত দেয় (BOOST_PP_FOR, স্ট্রিংফিকেশন, অ্যারে সাবস্ক্রিপ্ট এবং এর মতো)

আর্টিকেল রয়েছে: আবেল সিনকোভিক্স এবং ডেভ আব্রাহামস দ্বারা সি ++ টেম্পলেট রূপকগুলিতে স্ট্রিং ব্যবহার করা

আপনার ম্যাক্রো + BOOST_PP_REPEAT ব্যবহারের ধারণার তুলনায় এর কিছুটা উন্নতি হয়েছে - এর জন্য ম্যাক্রোতে সুস্পষ্ট আকার পাস করার প্রয়োজন হয় না। সংক্ষেপে, এটি স্ট্রিং আকার এবং "স্ট্রিং ওভাররন সুরক্ষা" এর জন্য উপরের সীমাটির উপর ভিত্তি করে:

template <int N>
constexpr char at(char const(&s)[N], int i)
{
    return i >= N ? '\0' : s[i];
}

প্লাস শর্তসাপেক্ষ বুস্ট :: এমপিএল :: পুশ_ব্যাক


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

আপনি যদি বর্ধিত ম্যাক্রোতে পিছনের জিরো, হাতের লিখিত ম্যাক্রো লুপিং, স্ট্রিংয়ের 2x পুনরাবৃত্তি গ্রহণ করেন এবং বুস্ট না রাখেন - তবে আমি সম্মত হই - এটি আরও ভাল। যদিও, বুস্টের সাথে এটি কেবল তিনটি লাইন হবে:

সরাসরি নমুনা

#include <boost/preprocessor/repetition/repeat.hpp>
#define GET_STR_AUX(_, i, str) (sizeof(str) > (i) ? str[(i)] : 0),
#define GET_STR(str) BOOST_PP_REPEAT(64,GET_STR_AUX,str) 0

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

আমি সম্মত - উদাহরণস্বরূপ, আমি হাওয়ার্ড হিন্যান্ট উদাহরণ পছন্দ করি।
ইভজেনি পানসিয়ুক

5

কেউ আমার উত্তরটি পছন্দ করে বলে মনে হচ্ছে না: - <। সুতরাং এখানে আমি কীভাবে একটি str_const একটি প্রকৃত প্রকারে রূপান্তর করব তা দেখাই:

#include <iostream>
#include <utility>

// constexpr string with const member functions
class str_const { 
private:
    const char* const p_;
    const std::size_t sz_;
public:

    template<std::size_t N>
    constexpr str_const(const char(&a)[N]) : // ctor
    p_(a), sz_(N-1) {}

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

    constexpr std::size_t size() const { return sz_; } // size()
};


template <char... letters>
struct string_t{
    static char const * c_str() {
        static constexpr char string[]={letters...,'\0'};
        return string;
    }
};

template<str_const const& str,std::size_t... I>
auto constexpr expand(std::index_sequence<I...>){
    return string_t<str[I]...>{};
}

template<str_const const& str>
using string_const_to_type = decltype(expand<str>(std::make_index_sequence<str.size()>{}));

constexpr str_const hello{"Hello World"};
using hello_t = string_const_to_type<hello>;

int main()
{
//    char c = hello_t{};        // Compile error to print type
    std::cout << hello_t::c_str();
    return 0;
}

ঝাঁকুনি ++ -stdlib = libc ++ -std = সি ++ 14 (ঝনক 3.7) দিয়ে সংকলন


ভাল কাজ করে তবে এমএসভিসি 2019 এর জন্য নয়, কারণ এটি স্ট্রাইস সাইজ () কনস্টেক্সপ্রপ না হওয়ার বিষয়ে অভিযোগ করে। পৃথকভাবে কর্তনকারী স্ট্রিংসাইজ () ব্যবহার করে ২ য় যোগ করে ঠিক করা যায়। হতে পারে এটি কিছু উপবিষ্টতা ধরে রেখেছে ;-)
জাকারিয়া 13

4

এখানে প্রতিটি সংকলন-সময় স্ট্রিং পাস করার জন্য একটি std :: tuple <char ...> তৈরির জন্য একটি সংযুক্ত সি ++ ১৪ সমাধান।

#include <tuple>
#include <utility>


namespace detail {
        template <std::size_t ... indices>
        decltype(auto) build_string(const char * str, std::index_sequence<indices...>) {
                return std::make_tuple(str[indices]...);
        }
}

template <std::size_t N>
constexpr decltype(auto) make_string(const char(&str)[N]) {
        return detail::build_string(str, std::make_index_sequence<N>());
}

auto HelloStrObject = make_string("hello");

এবং অন্য ম্যাক্রো পোস্ট থেকে ছাঁটা একটি অনন্য সংকলন-টাইপ টাইপ তৈরি করার জন্য এখানে একটি।

#include <utility>

template <char ... Chars>
struct String {};

template <typename Str, std::size_t ... indices>
decltype(auto) build_string(std::index_sequence<indices...>) {
        return String<Str().chars[indices]...>();
}

#define make_string(str) []{\
        struct Str { const char * chars = str; };\
        return build_string<Str>(std::make_index_sequence<sizeof(str)>());\
}()

auto HelloStrObject = make_string("hello");

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


প্রকৃতপক্ষে, তারা জিসিসি / কলং দ্বারা সমর্থিত একটি এক্সটেনশন ব্যবহার করতে পারে, তবে উত্তর হিসাবে পোস্ট করার আগে আমি মানটিতে এটি যুক্ত হওয়ার আগে অপেক্ষা করতে যাচ্ছি।
অকার্যকর-নির্দেশক

3

একটি সহকর্মী সঙ্কলন সময়ে স্মৃতিতে স্ট্রিংগুলি সংযুক্ত করার জন্য আমাকে চ্যালেঞ্জ করেছিলেন। এটি সংকলন সময়ে পৃথক স্ট্রিং ইনস্ট্যান্টেশন অন্তর্ভুক্ত। সম্পূর্ণ কোডের তালিকা এখানে রয়েছে:

//Arrange strings contiguously in memory at compile-time from string literals.
//All free functions prefixed with "my" to faciliate grepping the symbol tree
//(none of them should show up).

#include <iostream>

using std::size_t;

//wrapper for const char* to "allocate" space for it at compile-time
template<size_t N>
struct String {
    //C arrays can only be initialised with a comma-delimited list
    //of values in curly braces. Good thing the compiler expands
    //parameter packs into comma-delimited lists. Now we just have
    //to get a parameter pack of char into the constructor.
    template<typename... Args>
    constexpr String(Args... args):_str{ args... } { }
    const char _str[N];
};

//takes variadic number of chars, creates String object from it.
//i.e. myMakeStringFromChars('f', 'o', 'o', '\0') -> String<4>::_str = "foo"
template<typename... Args>
constexpr auto myMakeStringFromChars(Args... args) -> String<sizeof...(Args)> {
    return String<sizeof...(args)>(args...);
}

//This struct is here just because the iteration is going up instead of
//down. The solution was to mix traditional template metaprogramming
//with constexpr to be able to terminate the recursion since the template
//parameter N is needed in order to return the right-sized String<N>.
//This class exists only to dispatch on the recursion being finished or not.
//The default below continues recursion.
template<bool TERMINATE>
struct RecurseOrStop {
    template<size_t N, size_t I, typename... Args>
    static constexpr String<N> recurseOrStop(const char* str, Args... args);
};

//Specialisation to terminate recursion when all characters have been
//stripped from the string and converted to a variadic template parameter pack.
template<>
struct RecurseOrStop<true> {
    template<size_t N, size_t I, typename... Args>
    static constexpr String<N> recurseOrStop(const char* str, Args... args);
};

//Actual function to recurse over the string and turn it into a variadic
//parameter list of characters.
//Named differently to avoid infinite recursion.
template<size_t N, size_t I = 0, typename... Args>
constexpr String<N> myRecurseOrStop(const char* str, Args... args) {
    //template needed after :: since the compiler needs to distinguish
    //between recurseOrStop being a function template with 2 paramaters
    //or an enum being compared to N (recurseOrStop < N)
    return RecurseOrStop<I == N>::template recurseOrStop<N, I>(str, args...);
}

//implementation of the declaration above
//add a character to the end of the parameter pack and recurse to next character.
template<bool TERMINATE>
template<size_t N, size_t I, typename... Args>
constexpr String<N> RecurseOrStop<TERMINATE>::recurseOrStop(const char* str,
                                                            Args... args) {
    return myRecurseOrStop<N, I + 1>(str, args..., str[I]);
}

//implementation of the declaration above
//terminate recursion and construct string from full list of characters.
template<size_t N, size_t I, typename... Args>
constexpr String<N> RecurseOrStop<true>::recurseOrStop(const char* str,
                                                       Args... args) {
    return myMakeStringFromChars(args...);
}

//takes a compile-time static string literal and returns String<N> from it
//this happens by transforming the string literal into a variadic paramater
//pack of char.
//i.e. myMakeString("foo") -> calls myMakeStringFromChars('f', 'o', 'o', '\0');
template<size_t N>
constexpr String<N> myMakeString(const char (&str)[N]) {
    return myRecurseOrStop<N>(str);
}

//Simple tuple implementation. The only reason std::tuple isn't being used
//is because its only constexpr constructor is the default constructor.
//We need a constexpr constructor to be able to do compile-time shenanigans,
//and it's easier to roll our own tuple than to edit the standard library code.

//use MyTupleLeaf to construct MyTuple and make sure the order in memory
//is the same as the order of the variadic parameter pack passed to MyTuple.
template<typename T>
struct MyTupleLeaf {
    constexpr MyTupleLeaf(T value):_value(value) { }
    T _value;
};

//Use MyTupleLeaf implementation to define MyTuple.
//Won't work if used with 2 String<> objects of the same size but this
//is just a toy implementation anyway. Multiple inheritance guarantees
//data in the same order in memory as the variadic parameters.
template<typename... Args>
struct MyTuple: public MyTupleLeaf<Args>... {
    constexpr MyTuple(Args... args):MyTupleLeaf<Args>(args)... { }
};

//Helper function akin to std::make_tuple. Needed since functions can deduce
//types from parameter values, but classes can't.
template<typename... Args>
constexpr MyTuple<Args...> myMakeTuple(Args... args) {
    return MyTuple<Args...>(args...);
}

//Takes a variadic list of string literals and returns a tuple of String<> objects.
//These will be contiguous in memory. Trailing '\0' adds 1 to the size of each string.
//i.e. ("foo", "foobar") -> (const char (&arg1)[4], const char (&arg2)[7]) params ->
//                       ->  MyTuple<String<4>, String<7>> return value
template<size_t... Sizes>
constexpr auto myMakeStrings(const char (&...args)[Sizes]) -> MyTuple<String<Sizes>...> {
    //expands into myMakeTuple(myMakeString(arg1), myMakeString(arg2), ...)
    return myMakeTuple(myMakeString(args)...);
}

//Prints tuple of strings
template<typename T> //just to avoid typing the tuple type of the strings param
void printStrings(const T& strings) {
    //No std::get or any other helpers for MyTuple, so intead just cast it to
    //const char* to explore its layout in memory. We could add iterators to
    //myTuple and do "for(auto data: strings)" for ease of use, but the whole
    //point of this exercise is the memory layout and nothing makes that clearer
    //than the ugly cast below.
    const char* const chars = reinterpret_cast<const char*>(&strings);
    std::cout << "Printing strings of total size " << sizeof(strings);
    std::cout << " bytes:\n";
    std::cout << "-------------------------------\n";

    for(size_t i = 0; i < sizeof(strings); ++i) {
        chars[i] == '\0' ? std::cout << "\n" : std::cout << chars[i];
    }

    std::cout << "-------------------------------\n";
    std::cout << "\n\n";
}

int main() {
    {
        constexpr auto strings = myMakeStrings("foo", "foobar",
                                               "strings at compile time");
        printStrings(strings);
    }

    {
        constexpr auto strings = myMakeStrings("Some more strings",
                                               "just to show Jeff to not try",
                                               "to challenge C++11 again :P",
                                               "with more",
                                               "to show this is variadic");
        printStrings(strings);
    }

    std::cout << "Running 'objdump -t |grep my' should show that none of the\n";
    std::cout << "functions defined in this file (except printStrings()) are in\n";
    std::cout << "the executable. All computations are done by the compiler at\n";
    std::cout << "compile-time. printStrings() executes at run-time.\n";
}

আপনি কি নিশ্চিত যে এটি সংকলন সময়ে সম্পন্ন হয়েছে? কিছুক্ষণ আগে এ নিয়ে আলোচনা হয়েছে , এবং আমার কাছে ফলাফল পরিষ্কার নয়।
ডায়প

দৌড়াতে objdump -t a.out |grep myকিছুই পেল না। যখন আমি এই কোডটি টাইপ করতে শুরু করেছি তখন আমি constexprফাংশনগুলি থেকে সরিয়ে নিয়ে পরীক্ষা চালিয়েছিলাম এবং বাদ দেওয়া objdumpহলে সেগুলি দেখিয়েছিলাম constexpr। আমি 99.9% আত্মবিশ্বাসী এটি সংকলনের সময়ে ঘটে।
laতিলা

1
আপনি যদি বিচ্ছিন্নতা ( -S) এর দিকে লক্ষ্য করেন তবে দেখতে পাবেন যে সিসি (৪.7.২) constexprকম্পাইল-সময়ে কার্যত সমাধান করে । তবুও, সংকলন-সময়ে স্ট্রিংগুলি একত্রিত হয় না । পরিবর্তে, (যদি আমি এটি সঠিকভাবে ব্যাখ্যা করি) সেই "একত্রিত" স্ট্রিংগুলির প্রতিটি চরের জন্য, একটি নিজস্ব movbক্রিয়াকলাপ রয়েছে, যা আপনি খুঁজছেন এমন অপটিমাইজেশনটি যুক্তিযুক্ত।
12:30

2
সেটা সত্য. আমি আবার gcc ৪.৯ দিয়ে চেষ্টা করেছি এবং এটি এখনও একই কাজ করে। আমি সর্বদা ভাবতাম যদিও এটি সংকলকটি বোকা হয়ে গেছে। কেবল গতকালই আমি অন্য একটি সংকলক চেষ্টা করার চেষ্টা করেছি। ঝাঁকুনির সাথে, বাইটওয়াইজ মুভগুলি মোটেও নেই। জিসিসি সহ, -ওগুলি এগুলি থেকেও মুক্তি পায় তবে -ও 3 একই কাজ করে।
laতিলা নেভ

2

হাওয়ার্ড হিন্যান্টের ধারণার উপর ভিত্তি করে আপনি আক্ষরিক শ্রেণি তৈরি করতে পারেন যা একসাথে দুটি লিখিত যুক্ত করবে।

template<int>
using charDummy = char;

template<int... dummy>
struct F
{
    const char table[sizeof...(dummy) + 1];
    constexpr F(const char* a) : table{ str_at<dummy>(a)..., 0}
    {

    }
    constexpr F(charDummy<dummy>... a) : table{ a..., 0}
    {

    }

    constexpr F(const F& a) : table{ a.table[dummy]..., 0}
    {

    }

    template<int... dummyB>
    constexpr F<dummy..., sizeof...(dummy)+dummyB...> operator+(F<dummyB...> b)
    {
        return { this->table[dummy]..., b.table[dummyB]... };
    }
};

template<int I>
struct get_string
{
    constexpr static auto g(const char* a) -> decltype( get_string<I-1>::g(a) + F<0>(a + I))
    {
        return get_string<I-1>::g(a) + F<0>(a + I);
    }
};

template<>
struct get_string<0>
{
    constexpr static F<0> g(const char* a)
    {
        return {a};
    }
};

template<int I>
constexpr auto make_string(const char (&a)[I]) -> decltype( get_string<I-2>::g(a) )
{
    return get_string<I-2>::g(a);
}

constexpr auto a = make_string("abc");
constexpr auto b = a+ make_string("def"); // b.table == "abcdef" 

কোথা str_atথেকে আসছে?
mic_e

এটির মতোই str_at<int I>(const char* a) { return a[i]; }
চমকপ্রদ

2

আপনার পন্থা # 1 সঠিক।

যাইহোক, অ্যারের বাহ্যিক সংযোগ থাকা দরকার, সুতরাং কাজ করার জন্য 1 পদ্ধতির পেতে, আমাদের এই জাতীয় কিছু লিখতে হবে: constexpr const char str [] = "হ্যালো, ওয়ার্ল্ড";

না, সঠিক নয়। এটি ঝনঝন এবং জিসিসি সহ সংকলন করে। আমি আশা করি এটির মান সি ++ 11, তবে আমি কোনও ভাষা স্তরকারী নই।

#include <iostream>

template <char... letters>
struct string_t{
    static char const * c_str() {
        static constexpr char string[]={letters...,'\0'};
        return string;
    }
};

// just live with it, but only once
using Hello_World_t = string_t<'H','e','l','l','o',' ','w','o','r','l','d','!'>;

template <typename Name>
void print()
{
    //String as template parameter
    std::cout << Name::c_str();
}

int main() {
    std::cout << Hello_World_t::c_str() << std::endl;
    print<Hello_World_t>();
    return 0;
}

আমি সি ++ 17 এর জন্য যা পছন্দ করব তা হ'ল নীচের সমতুল্য হবে (সম্পূর্ণ পদ্ধতির কাছে # 1)

// for template <char...>
<"Text"> == <'T','e','x','t'>

টেম্পলেটযুক্ত ব্যবহারকারী সংজ্ঞায়িত আক্ষরিকের জন্য স্ট্যান্ডার্ডে খুব অনুরূপ কিছু ইতিমধ্যে বিদ্যমান, যেমন শূন্যপদ-নির্দেশক এছাড়াও উল্লেখ করেছেন, তবে কেবলমাত্র সংখ্যার জন্য। ততক্ষণে আর একটি ছোট কৌশল হ'ল ওভাররাইড সম্পাদনা মোড + অনুলিপি এবং এর পেস্ট ব্যবহার করা

string_t<' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '>;

আপনি যদি এই কাজগুলির চেয়ে ম্যাক্রোটিকে কিছু মনে করেন না (ইয়ানকস উত্তর থেকে কিছুটা সংশোধিত):

#define MACRO_GET_1(str, i) \
(sizeof(str) > (i) ? str[(i)] : 0)

#define MACRO_GET_4(str, i) \
MACRO_GET_1(str, i+0),  \
MACRO_GET_1(str, i+1),  \
MACRO_GET_1(str, i+2),  \
MACRO_GET_1(str, i+3)

#define MACRO_GET_16(str, i) \
MACRO_GET_4(str, i+0),   \
MACRO_GET_4(str, i+4),   \
MACRO_GET_4(str, i+8),   \
MACRO_GET_4(str, i+12)

#define MACRO_GET_64(str, i) \
MACRO_GET_16(str, i+0),  \
MACRO_GET_16(str, i+16), \
MACRO_GET_16(str, i+32), \
MACRO_GET_16(str, i+48)

//CT_STR means Compile-Time_String
#define CT_STR(str) string_t<MACRO_GET_64(#str, 0), 0 >//guard for longer strings

print<CT_STR(Hello World!)>();

2

একটি অনন্য সংকলন-টাইপ টাইপ তৈরির জন্য ক্যাসির সমাধান, ছোটখাটো পরিবর্তনগুলি সহ, সি ++ 11 এর সাথেও ব্যবহার করা যেতে পারে:

template <char... Chars>
struct string_t {};

namespace detail {
template <typename Str,unsigned int N,char... Chars>
struct make_string_t : make_string_t<Str,N-1,Str().chars[N-1],Chars...> {};

template <typename Str,char... Chars>
struct make_string_t<Str,0,Chars...> { typedef string_t<Chars...> type; };
} // namespace detail

#define CSTR(str) []{ \
    struct Str { const char *chars = str; }; \
    return detail::make_string_t<Str,sizeof(str)>::type(); \
  }()

ব্যবহার করুন:

template <typename String>
void test(String) {
  // ... String = string_t<'H','e','l','l','o','\0'>
}

test(CSTR("Hello"));

2

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

আমার সমস্যাটি হানা স্ট্রিংগুলির সাথে বুস্ট হানা মানচিত্রটি ব্যবহার করার সময়, সংকলকটি এখনও কিছু রানটাইম কোড তৈরি করেছে (নীচে দেখুন)। কারণটি স্পষ্টতই সংকলনকালে মানচিত্রটি জিজ্ঞাসা করা উচিত constexprBOOST_HANA_STRINGম্যাক্রো একটি ল্যাম্বদা উত্পন্ন করার কারণে এটি সম্ভব নয় , যা constexprপ্রসঙ্গে ব্যবহার করা যায় না । অন্যদিকে, মানচিত্রটির বিভিন্ন ধরণের হতে বিভিন্ন সামগ্রীর স্ট্রিং দরকার।

যেহেতু এই থ্রেডের সমাধানগুলি হয় ল্যাম্বডা ব্যবহার করছে বা বিভিন্ন সামগ্রীর জন্য বিভিন্ন ধরণের সরবরাহ করছে না, তাই আমি নিম্নলিখিত পদ্ধতির সহায়ক বলে মনে করেছি। এছাড়াও এটি হ্যাকি str<'a', 'b', 'c'>সিনট্যাক্স এড়ায় ।

প্রাথমিক ধারণাটি স্কট শুরের str_constচরিত্রগুলির হ্যাশটিতে প্রেরণ করা হয়েছে version এটি হয় c++14তবে ফাংশনটির c++11পুনরাবৃত্তিমূলক বাস্তবায়ন সম্ভব crc32( এখানে দেখুন ) see

// str_const from https://github.com/boostcon/cppnow_presentations_2012/blob/master/wed/schurr_cpp11_tools_for_class_authors.pdf?raw=true

    #include <string>

template<unsigned Hash>  ////// <- This is the difference...
class str_const2 { // constexpr string
private:
    const char* const p_;
    const std::size_t sz_;
public:
    template<std::size_t N>
    constexpr str_const2(const char(&a)[N]) : // ctor
        p_(a), sz_(N - 1) {}


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

    constexpr std::size_t size() const { return sz_; } // size()

    constexpr const char* const data() const {
        return p_;
    }
};

// Crc32 hash function. Non-recursive version of https://stackoverflow.com/a/23683218/8494588
static constexpr unsigned int crc_table[256] = {
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

template<size_t N>
constexpr auto crc32(const char(&str)[N])
{
    unsigned int prev_crc = 0xFFFFFFFF;
    for (auto idx = 0; idx < sizeof(str) - 1; ++idx)
        prev_crc = (prev_crc >> 8) ^ crc_table[(prev_crc ^ str[idx]) & 0xFF];
    return prev_crc ^ 0xFFFFFFFF;
}

// Conveniently create a str_const2
#define CSTRING(text) str_const2 < crc32( text ) >( text )

// Conveniently create a hana type_c<str_const2> for use in map
#define CSTRING_TYPE(text) hana::type_c<decltype(str_const2 < crc32( text ) >( text ))>

ব্যবহার:

#include <boost/hana.hpp>

#include <boost/hana/map.hpp>
#include <boost/hana/pair.hpp>
#include <boost/hana/type.hpp>

namespace hana = boost::hana;

int main() {

    constexpr auto s2 = CSTRING("blah");

    constexpr auto X = hana::make_map(
        hana::make_pair(CSTRING_TYPE("aa"), 1)
    );    
    constexpr auto X2 = hana::insert(X, hana::make_pair(CSTRING_TYPE("aab"), 2));   
    constexpr auto ret = X2[(CSTRING_TYPE("aab"))];
    return ret;
}

clang-cl5.0 সহ এসেম্বলারের কোডের ফলাফল :

012A1370  mov         eax,2  
012A1375  ret  

0

আমি @ ব্যবহারকারী1115339 এর উত্তরে দুটি খুব ছোট উন্নতি যুক্ত করতে চাই। আমি উত্তরের মন্তব্যে তাদের উল্লেখ করেছি, তবে সুবিধার জন্য আমি এখানে একটি অনুলিপি পেস্ট সমাধান রাখব।

পার্থক্যটি হ'ল FIXED_CSTRINGম্যাক্রো, যা শ্রেণি টেম্পলেটগুলির মধ্যে স্ট্রিংগুলি ব্যবহার করতে এবং সূচক অপারেটরের পক্ষে আর্গুমেন্ট হিসাবে (যদি আপনার কাছে একটি সংকলনের সময় মানচিত্র থাকে তবে দরকারী) allows

সরাসরি উদাহরণ

namespace  variadic_toolbox
{
    template<unsigned  count, 
        template<unsigned...> class  meta_functor, unsigned...  indices>
    struct  apply_range
    {
        typedef  typename apply_range<count-1, meta_functor, count-1, indices...>::result  result;
    };

    template<template<unsigned...> class  meta_functor, unsigned...  indices>
    struct  apply_range<0, meta_functor, indices...>
    {
        typedef  typename meta_functor<indices...>::result  result;
    };
}

namespace  compile_time
{
    template<char...  str>
    struct  string
    {
        static  constexpr  const char  chars[sizeof...(str)+1] = {str..., '\0'};
    };

    template<char...  str>
    constexpr  const char  string<str...>::chars[sizeof...(str)+1];

    template<typename  lambda_str_type>
    struct  string_builder
    {
        template<unsigned... indices>
        struct  produce
        {
            typedef  string<lambda_str_type{}.chars[indices]...>  result;
        };
    };
}

#define  CSTRING(string_literal)                                                        \
    []{                                                                                 \
        struct  constexpr_string_type { const char * chars = string_literal; };         \
        return  variadic_toolbox::apply_range<sizeof(string_literal)-1,                 \
            compile_time::string_builder<constexpr_string_type>::produce>::result{};    \
    }()


#define  FIXED_CSTRING(string_literal)                                                        \
    ([]{                                                                                 \
        struct  constexpr_string_type { const char * chars = string_literal; };         \
        return  typename variadic_toolbox::apply_range<sizeof(string_literal)-1,                 \
            compile_time::string_builder<constexpr_string_type>::template produce>::result{};    \
    }())    

struct A {

    auto test() {
        return FIXED_CSTRING("blah"); // works
        // return CSTRING("blah"); // works too
    }

    template<typename X>
    auto operator[](X) {
        return 42;
    }
};

template<typename T>
struct B {

    auto test() {       
       // return CSTRING("blah");// does not compile
       return FIXED_CSTRING("blah"); // works
    }
};

int main() {
    A a;
    //return a[CSTRING("blah")]; // fails with error: two consecutive ' [ ' shall only introduce an attribute before ' [ ' token
    return a[FIXED_CSTRING("blah")];
}

0

আমার নিজস্ব বাস্তবায়ন Boost.Hanaস্ট্রিং (ভেরেডিক অক্ষরের সাথে টেম্পলেট শ্রেণি) থেকে আসা পদ্ধতির উপর ভিত্তি করে তৈরি করা হয়েছে , তবে কেবলমাত্র C++11মান এবং constexprসংকলনকালীনতার উপর কঠোর চেক সহ ফাংশনগুলি ব্যবহার করে (সংকলন টাইম এক্সপ্রেশন না হলে একটি সংকলন সময় ত্রুটি হবে)। অভিনব পরিবর্তে {'a', 'b', 'c' }(একটি ম্যাক্রোর মাধ্যমে) স্বাভাবিক কাঁচা সি স্ট্রিং থেকে তৈরি করা যায় ।

বাস্তবায়ন: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/incolve/tacklelib/tackle/tmpl_string.hpp

পরীক্ষাগুলি: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/src/tests/unit/test_tmpl_string.cpp

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

const auto s0    = TACKLE_TMPL_STRING(0, "012");            // "012"
const char c1_s0 = UTILITY_CONSTEXPR_GET(s0, 1);            // '1'

const auto s1    = TACKLE_TMPL_STRING(0, "__012", 2);       // "012"
const char c1_s1 = UTILITY_CONSTEXPR_GET(s1, 1);            // '1'

const auto s2    = TACKLE_TMPL_STRING(0, "__012__", 2, 3);  // "012"
const char c1_s2 = UTILITY_CONSTEXPR_GET(s2, 1);            // '1'

// TACKLE_TMPL_STRING(0, "012") and TACKLE_TMPL_STRING(1, "012")
//   - semantically having different addresses.
//   So id can be used to generate new static array class field to store
//   a string bytes at different address.

// Can be overloaded in functions with another type to express the compiletimeness between functions:

template <uint64_t id, typename CharT, CharT... tchars>
const overload_resolution_1 & test_overload_resolution(const tackle::tmpl_basic_string<id, CharT, tchars...> &);
template <typename CharT>
const overload_resolution_2 & test_overload_resolution(const tackle::constexpr_basic_string<CharT> &);

// , where `constexpr_basic_string` is another approach which loses
//   the compiletimeness between function signature and body border,
//   because even in a `constexpr` function the compile time argument
//   looses the compiletimeness nature and becomes a runtime one.

একটি constexprক্রিয়া সংকলনের সময় সীমানা সম্পর্কে বিশদ : https://www.boost.org/doc/libs/1_65_0/libs/ana/doc/html/index.html#tutorial-appendix-constexpr

অন্যান্য ব্যবহারের বিশদগুলির জন্য পরীক্ষাগুলি দেখুন।

পুরো প্রকল্পটি বর্তমানে পরীক্ষামূলক।


0

সহায়ক ম্যাক্রো ফাংশন সহ সি ++ 17 এ সংকলন সময় স্ট্রিংগুলি তৈরি করা সহজ:

template <char... Cs>
struct ConstexprString
{
    static constexpr int size = sizeof...( Cs );
    static constexpr char buffer[size] = { Cs... };
};

template <char... C1, char... C2>
constexpr bool operator==( const ConstexprString<C1...>& lhs, const ConstexprString<C2...>& rhs )
{
    if( lhs.size != rhs.size )
        return false;

    return std::is_same_v<std::integer_sequence<char, C1...>, std::integer_sequence<char, C2...>>;
}




template <typename F, std::size_t... Is>
constexpr auto ConstexprStringBuilder( F f, std::index_sequence<Is...> )
{
    return ConstexprString<f( Is )...>{};
}

#define CONSTEXPR_STRING( x )                                              \
  ConstexprStringBuilder( []( std::size_t i ) constexpr { return x[i]; },  \
                 std::make_index_sequence<sizeof(x)>{} )

এবং এটি ব্যবহারের উদাহরণ:

auto n = CONSTEXPR_STRING( "ab" );
auto m = CONSTEXPR_STRING( "ab" );


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