একটি ক্লাসিক টেম্প্লেটিং সমস্যা। সি ++ স্ট্যান্ডার্ড লাইব্রেরি কীভাবে করে তার মতো একটি সাধারণ সমাধান এখানে। প্রাথমিক ধারণাটি একটি পুনরাবৃত্তাকার টেম্পলেট রয়েছে যা ভেক্টর নয় এমন কোনও ধরণের জন্য 0 এর বেস কেস সহ প্রতিটি মাত্রাকে এক এক করে গণনা করবে।
#include <vector>
#include <type_traits>
template<typename T>
struct dimensions : std::integral_constant<std::size_t, 0> {};
template<typename T>
struct dimensions<std::vector<T>> : std::integral_constant<std::size_t, 1 + dimensions<T>::value> {};
template<typename T>
inline constexpr std::size_t dimensions_v = dimensions<T>::value; // (C++17)
তাহলে আপনি এটি এর মতো ব্যবহার করতে পারেন:
dimensions<vector<vector<vector<int>>>>::value; // 3
// OR
dimensions_v<vector<vector<vector<int>>>>; // also 3 (C++17)
সম্পাদনা:
ঠিক আছে, আমি কোনও ধারক প্রকারের জন্য সাধারণ বাস্তবায়ন শেষ করেছি। লক্ষ্য করুন আমি কিছুই অভিব্যক্তি অনুযায়ী একটি সুগঠিত পুনরুক্তিকারীর টাইপ আছে হিসাবে একটি ধারক টাইপ সংজ্ঞায়িত begin(t)
যেখানে std::begin
ADL লুকআপ জন্য আমদানি ও হয় t
প্রকারের একটি lvalue হয় T
।
কেন স্টাফ কাজ করে এবং আমি যে পরীক্ষাগুলি ব্যবহার করি সেগুলি ব্যাখ্যা করার জন্য মন্তব্যের সাথে আমার কোডটি এখানে রয়েছে। দ্রষ্টব্য, এটি সংকলনের জন্য C ++ 17 প্রয়োজন।
#include <iostream>
#include <vector>
#include <array>
#include <type_traits>
using std::begin; // import std::begin for handling C-style array with the same ADL idiom as the other types
// decide whether T is a container type - i define this as anything that has a well formed begin iterator type.
// we return true/false to determing if T is a container type.
// we use the type conversion ability of nullptr to std::nullptr_t or void* (prefers std::nullptr_t overload if it exists).
// use SFINAE to conditionally enable the std::nullptr_t overload.
// these types might not have a default constructor, so return a pointer to it.
// base case returns void* which we decay to void to represent not a container.
template<typename T>
void *_iter_elem(void*) { return nullptr; }
template<typename T>
typename std::iterator_traits<decltype(begin(*(T*)nullptr))>::value_type *_iter_elem(std::nullptr_t) { return nullptr; }
// this is just a convenience wrapper to make the above user friendly
template<typename T>
struct container_stuff
{
typedef std::remove_pointer_t<decltype(_iter_elem<T>(nullptr))> elem_t; // the element type if T is a container, otherwise void
static inline constexpr bool is_container = !std::is_same_v<elem_t, void>; // true iff T is a container
};
// and our old dimension counting logic (now uses std:nullptr_t SFINAE logic)
template<typename T>
constexpr std::size_t _dimensions(void*) { return 0; }
template<typename T, std::enable_if_t<container_stuff<T>::is_container, int> = 0>
constexpr std::size_t _dimensions(std::nullptr_t) { return 1 + _dimensions<typename container_stuff<T>::elem_t>(nullptr); }
// and our nice little alias
template<typename T>
inline constexpr std::size_t dimensions_v = _dimensions<T>(nullptr);
int main()
{
std::cout << container_stuff<int>::is_container << '\n'; // false
std::cout << container_stuff<int[6]>::is_container<< '\n'; // true
std::cout << container_stuff<std::vector<int>>::is_container << '\n'; // true
std::cout << container_stuff<std::array<int, 3>>::is_container << '\n'; // true
std::cout << dimensions_v<std::vector<std::array<std::vector<int>, 2>>>; // 3
}
std::vector
রান-টাইম জিনিস, সংকলন-সময় নয়। আপনি যদি একটি সংকলন-সময়ের আকারের ধারক চান তবে দেখুনstd::array
। এছাড়াও; মনে রাখবেন যেconstexpr
কেবলমাত্র " সঙ্কলনের সময় মূল্যায়ন করা যেতে পারে" - এর কোনও প্রতিশ্রুতি থাকবে না। এটি রান-টাইমে মূল্যায়ন করা যেতে পারে।