সংকলনের সময় `কনস্ট চর * type টাইপের দুটি স্ট্রিং সংমিশ্রিত করা সম্ভব?


12

স্পষ্টতই আমরা একটি constexprফাংশনে দুটি স্ট্রিং লিটারেল সংমিশ্রণ করতে পারি , তবে স্ট্রিংয়ের সাথে একটি স্ট্রিংয়ের সাথে সংক্ষিপ্তকরণটি কি অন্য constexprফাংশন দ্বারা ফিরে এসেছে নীচের কোড হিসাবে?

template <class T>
constexpr const char * get_arithmetic_size()
{
    switch (sizeof(T))
    {
    case 1: return "1";
    case 2: return "2";
    case 4: return "4";
    case 8: return "8";
    case 16: return "16";
    default: static_assert(dependent_false_v<T>);
    }
}

template <class T>
constexpr std::enable_if_t<std::is_arithmetic_v<T>, const char *> make_type_name()
{
    const char * prefix = std::is_signed_v<T> ? "int" : "uint";
    return prefix; // how to concatenate prefix with get_arithmetic_size<T>() ?
}

static_assert(strings_equal(make_type_name<int>, make_type_name<int32_t>);

কোডটি একটি গণিতের ধরণের সংকলক-স্বতন্ত্র স্ট্রিং আইডেন্টিফায়ার করে।

EDIT1:

আরেকটু জটিল উদাহরণ হ'ল:

template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};

template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref> : std::true_type {};

template <class T>
constexpr std::enable_if_t<is_specialization<T, std::vector>::value || is_specialization<T, std::list>::value, const char *> make_type_name()
{
    return "sequence"; // + make_type_name<typename T::value_type>;
}

static_assert(strings_equal(make_type_name<std::vector<int>>(), make_type_name<std::list<int>>()));

2
বাইটস সহ একটি স্ট্যান্ড অ্যারে গ্রহণযোগ্য হবে? অন্যথায়, আপনি এটি করতে ম্যাক্রোগুলি এবং কোড জেন ব্যবহার করতে পারেন।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

@ ইয়াক্ক-অ্যাডামনেভ্র্যামন্ট হ্যাঁ, দেখে মনে হচ্ছে std::array(এবং সম্ভবত + বৈকল্পিক টেম্পলেট) এর চেয়ে ভাল কোনও সমাধান নেই
দিমিত্রিয়ানো

@ Yakk-AdamNevraumont concatenating এসটিডি :: অ্যারে: stackoverflow.com/questions/42749032/... : লাইভ উদাহরণ wandbox.org/permlink/VA85KCTqxiyS2rKE
Dmitriano

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

1
@ ডিমিট্রিয়ানো হ্যাঁ, আপনি খেয়াল করতে পারেন আমি এই প্রশ্নটি আগে দেখেছি ;)
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

উত্তর:


4

এখানে একটি দ্রুত সংকলন টাইম স্ট্রিং ক্লাস রয়েছে:

template<std::size_t N>
struct ct_str
{
    char state[N+1] = {0};
    constexpr ct_str( char const(&arr)[N+1] )
    {
        for (std::size_t i = 0; i < N; ++i)
            state[i] = arr[i];
    }
    constexpr char operator[](std::size_t i) const { return state[i]; } 
    constexpr char& operator[](std::size_t i) { return state[i]; } 

    constexpr explicit operator char const*() const { return state; }
    constexpr char const* data() const { return state; }
    constexpr std::size_t size() const { return N; }
    constexpr char const* begin() const { return state; }
    constexpr char const* end() const { return begin()+size(); }

    constexpr ct_str() = default;
    constexpr ct_str( ct_str const& ) = default;
    constexpr ct_str& operator=( ct_str const& ) = default;

    template<std::size_t M>
    friend constexpr ct_str<N+M> operator+( ct_str lhs, ct_str<M> rhs )
    {
        ct_str<N+M> retval;
        for (std::size_t i = 0; i < N; ++i)
            retval[i] = lhs[i];
        for (std::size_t i = 0; i < M; ++i)
            retval[N+i] = rhs[i];
        return retval;
    }

    friend constexpr bool operator==( ct_str lhs, ct_str rhs )
    {
        for (std::size_t i = 0; i < N; ++i)
            if (lhs[i] != rhs[i]) return false;
        return true;
    }
    friend constexpr bool operator!=( ct_str lhs, ct_str rhs )
    {
        for (std::size_t i = 0; i < N; ++i)
            if (lhs[i] != rhs[i]) return true;
        return false;
    }
    template<std::size_t M, std::enable_if_t< M!=N, bool > = true>
    friend constexpr bool operator!=( ct_str lhs, ct_str<M> rhs ) { return true; }
    template<std::size_t M, std::enable_if_t< M!=N, bool > = true>
    friend bool operator==( ct_str, ct_str<M> ) { return false; }
};

template<std::size_t N>
ct_str( char const(&)[N] )->ct_str<N-1>;

আপনি এটি এর মতো ব্যবহার করতে পারেন:

template <class T>
constexpr auto get_arithmetic_size()
{
    if constexpr (sizeof(T)==1)
        return ct_str{"1"};
    if constexpr (sizeof(T)==2)
        return ct_str{"2"};
    if constexpr (sizeof(T)==4)
        return ct_str{"4"};
    if constexpr (sizeof(T)==8)
        return ct_str{"8"};
    if constexpr (sizeof(T)==16)
        return ct_str{"16"};
}

template <class T, std::enable_if_t<std::is_arithmetic<T>{}, bool> = true>
constexpr auto make_type_name()
{
    if constexpr (std::is_signed<T>{})
        return ct_str{"int"} + get_arithmetic_size<T>();
    else
        return ct_str{"uint"} + get_arithmetic_size<T>();
}

যা বিবৃতি বাড়ে:

static_assert(make_type_name<int>() == make_type_name<int32_t>());

ক্ষণস্থায়ী।

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

এখন একটি বিরক্তিকর বিষয় হ'ল বাফারের দৈর্ঘ্য টাইপ সিস্টেমে। আপনি একটি lengthক্ষেত্র যোগ করতে পারেন এবং N"বাফার আকার" করতে ct_strপারেন , এবং কেবল অনুলিপি করতে lengthএবং অনুসরণযোগ্য বাইটগুলি এ হিসাবে ছেড়ে দিতে পারেন 0। তারপরে উভয় পক্ষের common_typeসর্বাধিক ফিরিয়ে দিতে ওভাররাইড করুন N

যে আপনি পাস না অনুমতি হবে ct_str{"uint"}এবং ct_str{"int"}মান একই ধরনের এবং একটি বিট কম বিরক্তিকর বাস্তবায়ন কোড আছে।

template<std::size_t N>
struct ct_str
{
    char state[N+1] = {0};

    template<std::size_t M, std::enable_if_t< (M<=N+1), bool > = true>
    constexpr ct_str( char const(&arr)[M] ):
        ct_str( arr, std::make_index_sequence<M>{} )
    {}
    template<std::size_t M, std::enable_if_t< (M<N), bool > = true >
    constexpr ct_str( ct_str<M> const& o ):
        ct_str( o, std::make_index_sequence<M>{} )
    {}
private:
    template<std::size_t M, std::size_t...Is>
    constexpr ct_str( char const(&arr)[M], std::index_sequence<Is...> ):
        state{ arr[Is]... }
    {}
    template<std::size_t M, std::size_t...Is>
    constexpr ct_str( ct_str<M> const& o, std::index_sequence<Is...> ):
        state{ o[Is]... }
    {}
public:
    constexpr char operator[](std::size_t i) const { return state[i]; } 
    constexpr char& operator[](std::size_t i) { return state[i]; } 

    constexpr explicit operator char const*() const { return state; }
    constexpr char const* data() const { return state; }
    constexpr std::size_t size() const {
        std::size_t retval = 0;
        while(state[retval]) {
            ++retval;
        }
        return retval;
    }
    constexpr char const* begin() const { return state; }
    constexpr char const* end() const { return begin()+size(); }

    constexpr ct_str() = default;
    constexpr ct_str( ct_str const& ) = default;
    constexpr ct_str& operator=( ct_str const& ) = default;

    template<std::size_t M>
    friend constexpr ct_str<N+M> operator+( ct_str lhs, ct_str<M> rhs )
    {
        ct_str<N+M> retval;
        for (std::size_t i = 0; i < lhs.size(); ++i)
            retval[i] = lhs[i];
        for (std::size_t i = 0; i < rhs.size(); ++i)
            retval[lhs.size()+i] = rhs[i];
        return retval;
    }

    template<std::size_t M>
    friend constexpr bool operator==( ct_str lhs, ct_str<M> rhs )
    {
        if (lhs.size() != rhs.size()) return false;
        for (std::size_t i = 0; i < lhs.size(); ++i)
            if (lhs[i] != rhs[i]) return false;
        return true;
    }
    template<std::size_t M>
    friend constexpr bool operator!=( ct_str lhs, ct_str<M> rhs )
    {
        if (lhs.size() != rhs.size()) return true;
        for (std::size_t i = 0; i < lhs.size(); ++i)
            if (lhs[i] != rhs[i]) return true;
        return false;
    }
};

template<std::size_t N>
ct_str( char const(&)[N] )->ct_str<N-1>;

ফাংশন বাস্তবায়ন এখন হয়ে:

template <class T>
constexpr ct_str<2> get_arithmetic_size()
{
    switch (sizeof(T)) {
        case 1: return "1";
        case 2: return "2";
        case 4: return "4";
        case 8: return "8";
        case 16: return "16";
    }

}

template <class T, std::enable_if_t<std::is_arithmetic<T>{}, bool> = true>
constexpr auto make_type_name()
{
    constexpr auto base = std::is_signed<T>{}?ct_str{"int"}:ct_str{"uint"};
    return base + get_arithmetic_size<T>();
}

যা লিখতে অনেক বেশি স্বাভাবিক।

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


শান্ত! এটা ব্যবহার করা উত্তম elseমধ্যে get_arithmetic_sizeদিয়ে if constexprএমনকি যদি আপনি না return, কারণ ছাড়া elseকথন dependent_false_v<T>ব্যর্থ হবে।
দিমিত্রিও

দ্বিতীয় বিকল্প চরম শান্ত!
দিমিত্রিও

4

না, এটা অসম্ভব। আপনি নীচের মতো কিছু বাস্তবায়ন করতে পারেন (এটি সি ++ ১৪)।

#include <cmath>
#include <cstring>
#include <iostream>
#include <type_traits>

constexpr const char* name[] = {
  "uint1", "uint2", "uint4", "uint8", "uint16",
  "int1",  "int2",  "int4",  "int8",  "int16"
};

template <class T>
constexpr std::enable_if_t<std::is_arithmetic<T>::value, const char *> make_type_name() {
  return name[std::is_signed<T>::value * 5 +
    static_cast<int>(std::log(sizeof(T)) / std::log(2) + 0.5)];
}

static_assert(std::strcmp(make_type_name<int>(), make_type_name<int32_t>()) == 0);

int main() {
  std::cout << make_type_name<int>();
  return 0;
}

https://ideone.com/BaADaM

আপনি যদি ব্যবহার পছন্দ না করেন তবে আপনি <cmath>প্রতিস্থাপন করতে পারেন std::log:

#include <cstring>
#include <iostream>
#include <type_traits>

constexpr const char* name[] = {
  "uint1", "uint2", "uint4", "uint8", "uint16",
  "int1",  "int2",  "int4",  "int8",  "int16"
};

constexpr size_t log2(size_t n) {
  return (n<2) ? 0 : 1 + log2(n/2);
}

template <class T>
constexpr std::enable_if_t<std::is_arithmetic<T>::value, const char *> make_type_name() {
  return name[std::is_signed<T>::value * 5 + log2(sizeof(T))];
}

static_assert(std::strcmp(make_type_name<int>(), make_type_name<int32_t>()) == 0);

int main() {
  std::cout << make_type_name<int>();
  return 0;
}

std::logআমার পক্ষে খুব জটিল, স্ট্রিংগুলি
স্ট্র্যাঙ্কেট

এটি একটি constexpr, সম্পর্কে চিন্তা করবেন না std::log()। আপনি এটি প্রতিস্থাপন করতে পারেন, তবে কোডটি বড় করা হবে
এসএম

আপনার কাছে EDIT1 এর উদাহরণ আছে?
দিমিত্রিও

4
আমার জানা মতে, এর তন্ন তন্ন std::logনা std::strcmpহতে নিশ্চিত করা হয় constexpr। প্রকৃতপক্ষে, মানটি সুনির্দিষ্টভাবে তাদের constexprC ++ 14 সাল থেকে নিষেধ করে । সুতরাং, আপনার কোডটি আসলে অ-মানক এক্সটেনশানগুলি ব্যবহার করে।
এলএফ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.