আমি একপ্রকার হতবাক হয়ে গিয়েছিলাম যে কাজটি করার জন্য কেউ কোনও পাটিগণিত-যাদু ভিত্তিক লুপ প্রস্তাব করেনি। যেহেতু সি ওয়াং কোনও নেস্টেড লুপগুলি ছাড়াই সমাধান খুঁজছেন , তাই আমি এর প্রস্তাব দেব:
double B[10][8][5];
int index = 0;
while (index < (10 * 8 * 5))
{
const int x = index % 10,
y = (index / 10) % 10,
z = index / 100;
do_something_on_B(B[x][y][z]);
++index;
}
ভাল, এই পদ্ধতির মার্জিত এবং নমনীয় নয়, তাই আমরা সমস্ত প্রক্রিয়া একটি টেমপ্লেট ফাংশনে প্যাক করতে পারি:
template <typename F, typename T, int X, int Y, int Z>
void iterate_all(T (&xyz)[X][Y][Z], F func)
{
const int limit = X * Y * Z;
int index = 0;
while (index < limit)
{
const int x = index % X,
y = (index / X) % Y,
z = index / (X * Y);
func(xyz[x][y][z]);
++index;
}
}
এই টেম্পলেট ফাংশনটি নেস্টেড লুপগুলির আকারেও প্রকাশ করা যেতে পারে:
template <typename F, typename T, int X, int Y, int Z>
void iterate_all(T (&xyz)[X][Y][Z], F func)
{
for (auto &yz : xyz)
{
for (auto &z : yz)
{
for (auto &v : z)
{
func(v);
}
}
}
}
এবং প্রতিটি আকারের আকার গণনা করার জন্য প্যারামিটার ছাড়ের কঠোর পরিশ্রম করতে দিয়ে সালিশি আকারের সাথে ফাংশন নামের একটি 3 ডি অ্যারে সরবরাহ করে ব্যবহার করা যেতে পারে:
int main()
{
int A[10][8][5] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
int B[7][99][8] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
iterate_all(A, do_something_on_A);
iterate_all(B, do_something_on_B);
return 0;
}
আরও জেনেরিকের দিকে
তবে আবারও, এতে নমনীয়তার অভাব রয়েছে কারণ এটি কেবল 3 ডি অ্যারেগুলির জন্যই কাজ করে, তবে SFINAE ব্যবহার করে আমরা একটি স্বেচ্ছাচারিত মাত্রার অ্যারেগুলির জন্য কাজ করতে পারি, প্রথমে আমাদের একটি টেম্পলেট ফাংশন প্রয়োজন যা র্যাঙ্ক 1 এর অ্যারেগুলিকে পুনরাবৃত্তি করে :
template<typename F, typename A>
typename std::enable_if< std::rank<A>::value == 1 >::type
iterate_all(A &xyz, F func)
{
for (auto &v : xyz)
{
func(v);
}
}
এবং অন্য এক যা পুনরাবৃত্তি করে যে কোনও র্যাঙ্কের অ্যারেগুলিকে পুনরাবৃত্তি করে:
template<typename F, typename A>
typename std::enable_if< std::rank<A>::value != 1 >::type
iterate_all(A &xyz, F func)
{
for (auto &v : xyz)
{
iterate_all(v, func);
}
}
এটি আমাদেরকে স্বেচ্ছাচারিত আকারের অ্যারেটারি-আকারের সমস্ত মাত্রায় সমস্ত উপাদানগুলিকে পুনরাবৃত্তি করতে দেয়।
সাথে কাজ করা std::vector
একাধিক নেস্টেড ভেক্টরের জন্য, সমাধানটি সালিশী-মাত্রাগুলি স্বেচ্ছাসৈনিক আকারের অ্যারেগুলির মধ্যে একটিটিকে পুনরায় সাজিয়ে তোলে তবে SFINAE ছাড়াই: প্রথমে আমাদের একটি টেম্পলেট ফাংশন প্রয়োজন যা এর পুনরাবৃত্তি করে std::vector
এবং পছন্দসই ফাংশনটি কল করে:
template <typename F, typename T, template<typename, typename> class V>
void iterate_all(V<T, std::allocator<T>> &xyz, F func)
{
for (auto &v : xyz)
{
func(v);
}
}
এবং অন্য একটি টেম্পলেট ফাংশন যা কোনও ধরণের ভেক্টরকে পুনরাবৃত্তি করে এবং নিজেকে কল করে:
template <typename F, typename T, template<typename, typename> class V>
void iterate_all(V<V<T, std::allocator<T>>, std::allocator<V<T, std::allocator<T>>>> &xyz, F func)
{
for (auto &v : xyz)
{
iterate_all(v, func);
}
}
নেস্টিং স্তর নির্বিশেষে, iterate_all
ভেক্টর-অফ-ভ্যালু সংস্করণকে কল করা হবে যদি না ভেক্টর অফ-ভ্যালু সংস্করণ আরও ভাল ম্যাচ না হয় যার ফলে পুনরাবৃত্তির অবসান হয়।
int main()
{
using V0 = std::vector< std::vector< std::vector<int> > >;
using V1 = std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > >;
V0 A0 = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
V1 A1 = {{{{{9, 8}, {7, 6}}, {{5, 4}, {3, 2}}}}};
iterate_all(A0, do_something_on_A);
iterate_all(A1, do_something_on_A);
return 0;
}
আমি মনে করি যে ফাংশনটি বডিটি বেশ সহজ এবং সোজা-এগিয়ে রয়েছে ... আমি ভাবছি যে সংকলকটি এই লুপগুলি আনারল করতে পারত (আমি প্রায় নিশ্চিত যে বেশিরভাগ সংকলক প্রথম উদাহরণটি আনলোল করতে পারে)।
এখানে লাইভ ডেমো দেখুন ।
আশা করি এটা সাহায্য করবে.