c++ - কিভাবে সি অ্যারে প্রারম্ভিকীকরণ "int arr[]={e1, e2, e3,...}" std:: array সহ আচরণ?




arrays templates (6)

(দ্রষ্টব্য: এই প্রশ্নটি উপাদানগুলির সংখ্যা নির্দিষ্ট করার বিষয়ে নয় এবং এখনও নেস্টেড প্রকারগুলিকে সরাসরি শুরু করার অনুমতি দেয়।)
এই প্রশ্ন int arr[20]; মত একটি সি অ্যারের জন্য বাম ব্যবহার আলোচনা int arr[20];তার জবাবে , @ জেমস কানজ সি অ্যারের সর্বশেষ দুর্গগুলির একটি দেখায়, এটি অনন্য সূত্রপাত বৈশিষ্ট্য:

int arr[] = { 1, 3, 3, 7, 0, 4, 2, 0, 3, 1, 4, 1, 5, 9 };

আমরা উপাদান সংখ্যার উল্লেখ করতে হবে না, hooray! এখন সি ++ 11 ফাংশনগুলির সাথে এটির পুনরাবৃত্তি করুন std::begin এবং std::end <iterator> ( অথবা আপনার নিজস্ব রূপ ) থেকে std::end এবং আপনার আকারের এমনকি চিন্তা করার প্রয়োজন নেই।

এখন, std::array সাথে এটি অর্জনের কোনও (সম্ভবত টিএমপি) উপায় রয়েছে? ম্যাক্রো ব্যবহার এটি nicer দেখতে অনুমতি দেওয়া। :)

??? std_array = { "here", "be", "elements" };

সম্পাদনা : বিভিন্ন উত্তর থেকে সংকলিত অন্তর্বর্তী সংস্করণ, এই রকম দেখাচ্ছে:

#include <array>
#include <utility>

template<class T, class... Tail, class Elem = typename std::decay<T>::type>
std::array<Elem,1+sizeof...(Tail)> make_array(T&& head, Tail&&... values)
{
  return { std::forward<T>(head), std::forward<Tail>(values)... };
}

// in code
auto std_array = make_array(1,2,3,4,5);

এবং সব ধরনের শীতল C ++ 11 স্টাফ নিয়োগ করে:

  • ভেরিয়েড টেমপ্লেট
  • sizeof...
  • Rvalue রেফারেন্স
  • নিখুঁত ফরওয়ার্ডিং
  • std::array , অবশ্যই
  • ইউনিফর্ম প্রাথমিককরণ
  • ইউনিফর্ম প্রারম্ভিক সঙ্গে রিটার্ন টাইপ omitting
  • টাইপ পরিমাপ ( auto )

এবং একটি উদাহরণ here পাওয়া here

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

struct A{ int a; int b; };

// C syntax
A arr[] = { {1,2}, {3,4} };
// using std::array
??? std_array = { {1,2}, {3,4} };

এছাড়াও, প্রাথমিককরণ সংখ্যা বাস্তবায়ন দ্বারা সমর্থিত ফাংশন এবং টেমপ্লেট আর্গুমেন্ট সংখ্যা সীমাবদ্ধ।


(@Dyp দ্বারা সমাধান)

দ্রষ্টব্য: সি ++ 14 ( std::index_sequence ) প্রয়োজন। যদিও সি ++ 11 এ std::index_sequence প্রয়োগ করতে পারে।

#include <iostream>

// ---

#include <array>
#include <utility>

template <typename T>
using c_array = T[];

template<typename T, size_t N, size_t... Indices>
constexpr auto make_array(T (&&src)[N], std::index_sequence<Indices...>) {
    return std::array<T, N>{{ std::move(src[Indices])... }};
}

template<typename T, size_t N>
constexpr auto make_array(T (&&src)[N]) {
    return make_array(std::move(src), std::make_index_sequence<N>{});
}

// ---

struct Point { int x, y; };

std::ostream& operator<< (std::ostream& os, const Point& p) {
    return os << "(" << p.x << "," << p.y << ")";
}

int main() {
    auto xs = make_array(c_array<Point>{{1,2}, {3,4}, {5,6}, {7,8}});

    for (auto&& x : xs) {
        std::cout << x << std::endl;
    }

    return 0;
}

আমি একটি সহজ make_array আশা করি।

template<typename ret, typename... T> std::array<ret, sizeof...(T)> make_array(T&&... refs) {
    // return std::array<ret, sizeof...(T)>{ { std::forward<T>(refs)... } };
    return { std::forward<T>(refs)... };
}

একটি অ্যারে সৃষ্টিকর্তা টাইপ তৈরি করুন।

এটি পূর্বের মাধ্যমে রেফারেন্সের মাধ্যমে প্রতিটি উপাদানকে শৃঙ্খলিত একটি এক্সপ্রেশন টেম্পলেট তৈরি করতে operator, ওভারলোড করে।

একটি ফ্রী ফাংশন যোগ করুন যা অ্যারে তৈরি করে এবং রেফারেন্সের শৃঙ্খলে সরাসরি একটি অ্যারে তৈরি করে।

সিনট্যাক্স এই মত কিছু চেহারা উচিত:

auto arr = finish( make_array<T>->* 1,2,3,4,5 );

এটি {} ভিত্তিক নির্মাণের অনুমতি দেয় না, শুধুমাত্র operator= হিসাবে। আপনি ব্যবহার করতে ইচ্ছুক হলে = আমরা এটি কাজ পেতে পারেন:

auto arr = finish( make_array<T>= {1}={2}={3}={4}={5} );

অথবা

auto arr = finish( make_array<T>[{1}][{2}[]{3}][{4}][{5}] );

এর মধ্যে কেউ ভাল সমাধান মত চেহারা।

ভেরার্ডিক্স ব্যবহার করে আপনার কম্পাইলার-লঙ্ঘন সীমা এবং VarGs এবং ব্লকগুলির {} উপাদানের জন্য পুনরাবৃত্ত ব্যবহারের সীমাতে সীমাবদ্ধ করে।

শেষ পর্যন্ত, সত্যিই একটি ভাল সমাধান নেই।

আমি যা করি তা হল আমি আমার কোড লিখি তাই এটি উভয় T[] এবং std::array তথ্য উভয় খেয়ে ফেলে - এটি যত্ন করে না যে এটি আমি যত্ন নিই। কখনও কখনও এই আমার ফরওয়ার্ডিং কোড std::array স্বচ্ছভাবে [] অ্যারে চালু করতে হবে মানে।


পূর্ববর্তী পোস্টগুলির কয়েকটি ধারণা মিশ্রিত করে, এখানে একটি সমাধান যা নেস্টেড নির্মাণের জন্য কাজ করে (GCC4.6 এ পরীক্ষিত):

template <typename T, typename ...Args>
std::array<T, sizeof...(Args) + 1> make_array(T && t, Args &&... args)
{
  static_assert(all_same<T, Args...>::value, "make_array() requires all arguments to be of the same type."); // edited in
  return std::array<T, sizeof...(Args) + 1>{ std::forward<T>(t), std::forward<Args>(args)...};
}

অদ্ভুত, ফেরত মান একটি rvalue রেফারেন্স করতে পারেন না, যে নেস্টেড নির্মাণের জন্য কাজ করবে না। যাইহোক, এখানে একটি পরীক্ষা:

auto q = make_array(make_array(make_array(std::string("Cat1"), std::string("Dog1")), make_array(std::string("Mouse1"), std::string("Rat1"))),
                    make_array(make_array(std::string("Cat2"), std::string("Dog2")), make_array(std::string("Mouse2"), std::string("Rat2"))),
                    make_array(make_array(std::string("Cat3"), std::string("Dog3")), make_array(std::string("Mouse3"), std::string("Rat3"))),
                    make_array(make_array(std::string("Cat4"), std::string("Dog4")), make_array(std::string("Mouse4"), std::string("Rat4")))
                    );

std::cout << q << std::endl;
// produces: [[[Cat1, Dog1], [Mouse1, Rat1]], [[Cat2, Dog2], [Mouse2, Rat2]], [[Cat3, Dog3], [Mouse3, Rat3]], [[Cat4, Dog4], [Mouse4, Rat4]]]

(শেষ আউটপুটের জন্য আমি আমার pretty-printer ব্যবহার করছি।)

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

template <typename T, typename ...Args>
typename std::enable_if<all_same<T, Args...>::value, std::array<T, sizeof...(Args) + 1>>::type
make_array(T && t, Args &&... args)
{
  return std::array<T, sizeof...(Args) + 1> { std::forward<T>(t), std::forward<Args>(args)...};
}

all_same<Args...> উপায়ে, আপনাকে all_same<Args...> ধরন বৈশিষ্ট্য প্রয়োজন হবে। এখানে এটি std::is_same<S, T> থেকে সাধারণকরণ করা হচ্ছে ( T , T& T const & ইত্যাদি মিশ্রণের জন্য ক্ষয়ক্ষতি গুরুত্বপূর্ণ।)

template <typename ...Args> struct all_same { static const bool value = false; };
template <typename S, typename T, typename ...Args> struct all_same<S, T, Args...>
{
  static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value && all_same<T, Args...>::value;
};
template <typename S, typename T> struct all_same<S, T>
{
  static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value;
};
template <typename T> struct all_same<T> { static const bool value = true; };

উল্লেখ্য যে make_array() অনুলিপি অনুলিপি দ্বারা প্রদান করে, যা কম্পাইলার (পর্যাপ্ত অপ্টিমাইজেশান ফ্ল্যাগের সাহায্যে!) র্যালিউ হিসাবে আচরণ করতে বা অন্যথায় অপটিমাইজ করার অনুমতি দেয় এবং std::array একটি সমষ্টিগত ধরন, তাই কম্পাইলারটি বিনামূল্যে সর্বোত্তম সম্ভব নির্মাণ পদ্ধতি বাছাই করা।

অবশেষে, নোট করুন যে make_array সেট আপ করার সময় আপনি কপি / সরানো নির্মাণ এড়াতে পারবেন না। সুতরাং std::array<Foo,2> x{Foo(1), Foo(2)}; কোন অনুলিপি / সরানো নেই, তবে auto x = make_array(Foo(1), Foo(2)); আর্গুমেন্টগুলিকে make_array ফরোয়ার্ড হিসাবে দুটি কপি / চালান আছে। আমি মনে করি না যে আপনি এটিকে উন্নত করতে পারেন, কারন আপনি সাহায্যকারীকে একটি বৈকল্পিক প্রাথমিক তালিকা তালিকাটি পাস করতে এবং টাইপ এবং আকার কমানো করতে পারবেন না - যদি প্রিপপ্রসেসরটির আকার ছিল sizeof... ভেরিয়েডিক আর্গুমেন্টগুলির জন্য ফাংশন, সম্ভবত এটি হতে পারে সম্পন্ন, কিন্তু মূল ভাষা মধ্যে না।



সেরা আমি মনে করতে পারেন:

template<class T, class... Tail>
auto make_array(T head, Tail... tail) -> std::array<T, 1 + sizeof...(Tail)>
{
     std::array<T, 1 + sizeof...(Tail)> a = { head, tail ... };
     return a;
}

auto a = make_array(1, 2, 3);

যাইহোক, এর জন্য কম্পাইলারকে এনআরভিও করতে হবে এবং তারপরেও ফেরত মানের অনুলিপিটি বাদ দেওয়া দরকার (যা বৈধ কিন্তু প্রয়োজনীয় নয়)। অনুশীলনে, আমি যেকোন সি ++ কম্পাইলারকে এমনভাবে অপ্টিমাইজ করতে সক্ষম হব যে এটি সরাসরি সূচনা হিসাবে দ্রুত।






c++11