C++ Wrapper Class to Mimic The Behavoir of a C Array’s Initialization

I have an inheritance class that mimic the behavior of C style array’s initialization by using a class template that has a variadic constructor but the template itself is not a variadic template. The base class stores the contents from two flavors of constructors either a Variadic Constructor, or a Variadic Constructor that takes an std::initializer_list as it’s parameter. The base class also contains a size that is inferred by its populated member vector, a function to return its size and an overloaded operator operator()() that will return its internal vector.

The child class inherits this functionality. It only has one member and that is a pointer to <T>. It has the corresponding matching constructors as its parent class, a set of overloaded subscript-indexing operators and a public method to retrieve it’s internal pointer. This class’s internal pointer is set to point to its parent’s internal vector’s data.

As far as I can tell the appears to be bug free to the best of my knowledge and it is producing expected values. Here is what I have so far.


#include <vector> #include <string> #include <sstream> #include <iostream> #include <exception> #include <type_traits> #include <initializer_list> #include <utility>  template<typename T> class ParamPack { protected:     std::vector<T> values_;     size_t size_; public:     template<typename... U>     ParamPack( U... u ) : values_{ static_cast<T>(u)... } {         size_ = values_.size();     }      template<typename ... U>     ParamPack( std::initializer_list<std::is_same<T, U...>( U...)> il ) : values_( il ) {         size_ = values_.size();     }      std::vector<T> operator()() {         return values_;     }      const size_t size() const { return size_; } };  template<typename T> class Array : public ParamPack<T> { private:     T* items_; public:      template<typename... U>     Array( U... u ) : ParamPack<T>::ParamPack( u... ) {         items_ =  this->values_.data();     }      template<typename... U>     Array( std::initializer_list<U...> il ) : ParamPack<T>::ParamPack( il ) {         items_ = this->values_.data();     }      T& operator[]( int idx ) {         return items_[idx];     }      T operator[]( int idx ) const {         return items_[idx];     }      T* data() const { return items_; }  };  int main() {     try {         // Parameter Pack Examples:         // Variadic Constructor { ... }         std::cout << "ParamPack<T> Examples:\n";         std::cout << "Using ParamPack<T>'s Variadic Constructor\n";         ParamPack<int> pp1( 1, 2, 3, 4  );         std::cout << "Size: " << pp1.size() << " | Elements: ";         for( auto& v : pp1() ) {             std::cout << v << " ";         }         std::cout << '\n';               //std::initializer_list<int> il{ 1,2,3,4 };         std::cout << "Using ParamPack<T>'s Initializer List\n";         ParamPack<int> pp2( { 5, 6, 7, 8 } );         std::cout << "Size: " << pp2.size() << " | Elements: ";         for( auto& v : pp2() ) {             std::cout << v << " ";         }         std::cout << "\n\n";          // Array Examples:         // Using  Variadic Constructor         std::cout << "Array<T> Examples:\n";         std::cout << "Using Array<T>'s Variadic Constructor\n";         Array<int> testA( 9, 8, 7, 6 );         for( size_t i = 0; i < testA.size(); i++ ) {             std::cout << testA[i] << " ";         }         std::cout << '\n';          Array<std::string> testB( "Hello", " World" );         for( size_t i = 0; i < testB.size(); i++ ) {             std::cout << testB[i] << " ";         }         std::cout << "\n\n";          // Using Constructor w/ Initializer List         std::cout << "Using Array<T>'s Constructor with Initializer List\n";         Array<int> testC( { 105, 210, 420 } );         for( size_t i = 0; i < testC.size(); i++ ) {             std::cout << testC[i] << " ";         }         std::cout << "\n\n";          // Using Initializer List with =         std::cout << "Using Array<T>'s Initializer List with =\n";         Array<int> a = { 1, 2, 3, 4 };         for( size_t i = 0; i < a.size(); i++ ) {             std::cout << a[i] << " ";         }         std::cout << '\n';                          Array<char> b = { 'a', 'b', 'c', 'd' };         for ( size_t i = 0; i < b.size(); i++ ) {             std::cout << b[i] << " ";         }         std::cout << '\n';          Array<double> c = { 1.2, 3.4, 4.5, 6.7 };         for( size_t i = 0; i < c.size(); i++ ) {             std::cout << c[i] << " ";         }         std::cout << "\n\n";           // Using Initializer List directly         std::cout << "Using Array<T>'s Initalizer List directly\n";         Array<uint32_t> a1{ 3, 6, 9, 12 };         for( size_t i = 0; i < a1.size(); i++ ) {             std::cout << a1[i] << " ";         }         std::cout << "\n\n";          // Using user defined data type         struct Point {             int x_, y_;             Point( int x, int y ) : x_( x ), y_( y ) {}         };         Point p1( 1, 2 ), p2( 3, 4 ), p3( 5, 6 );          // Variadic Constructor         std::cout << "Using Array<T>'s Variadic Consturctor with user data type\n";         Array<Point> d1( p1, p2, p3 );         for( size_t i = 0; i < d1.size(); i++ ) {             std::cout << "(" << d1[i].x_ << "," << d1[i].y_ << ") ";         }         std::cout << '\n';          // Initializer List Construtor (reversed order)         std::cout << "Using Array<T>'s Initializer List Constructor with user data type\n";         Array<Point> d2( { p3, p2, p1 } );         for( size_t i = 0; i < d2.size(); i++ ) {             std::cout << "(" << d2[i].x_ << "," << d2[i].y_ << ") ";         }         std::cout << '\n';          // Initializer List Version = {...} p2 first         std::cout << "Using Array<T>'s  = Initializer List with user data type\n";         Array<Point> d3 = { p2, p1, p3 };         for( size_t i = 0; i < d3.size(); i++ ) {             std::cout << "(" << d3[i].x_ << "," << d3[i].y_ << ") ";         }         std::cout << '\n';          // Initializer List Directly p2 first p1 & p3 swapped         std::cout << "Using Array<T>'s Initializer List directly with user data type\n";         Array<Point> d4{ p2, p3, p1 };         for( size_t i = 0; i < d4.size(); i++ ) {             std::cout << "(" << d4[i].x_ << "," << d4[i].y_ << ") ";         }         std::cout << "\n\n";                  // Need a local copy of the vector instead?         std::cout << "Using Array<T>'s base class's operator()() to retrieve vector\n";         std::vector<Point> points = d4(); // using operator()()         for( auto& p : points ) {             std::cout << "(" << p.x_ << "," << p.y_ << ") ";         }         std::cout << '\n';          // Need a local copy of the pointer instead?         std::cout << "Using Array<T>'s data() to get the contents of its internal pointer\n";         Point* pPoint = nullptr;         pPoint = d4.data();         for( size_t i = 0; i < d4.size(); i++ ) {             std::cout << "(" << pPoint[i].x_ << "," << pPoint[i].y_ << ") ";         }         std::cout << '\n';          // Will Not Compile: Must Be Instantiated By Type Explicitly         // Array e( 1, 2, 3, 4 );         // Array e( { 1,2,3,4 } );         // Array f{ 1, 2, 3, 4 };         // Array g = { 1,2,3,4 };          } catch( const std::runtime_error& e ) {         std::cerr << e.what() << '\n';         return EXIT_FAILURE;     }      return EXIT_SUCCESS; } 

-Output-

ParamPack<T> Examples: Using ParamPack<T>'s Variadic Constructor Size: 4 | Elements: 1 2 3 4 Using ParamPack<T>'s Initializer List Size: 5 | Elements: 5 6 7 8   Array<T> Examples: Using Array<T>'s Variadic Constructor 9 8 7 6 Hello World  Using Array<T>'s Constructor with Initializer List 105 210 420  Using Array<T>'s Initializer List with = 1 2 3 4 a b c d 1.2 3.4 5.6 7.8  Using Array<T>'s Initializer List directly 3 6 9 12  Using Array<T>'s Variadic Constructor with user data type (1,2) (3,4) (5,6) Using Array<T>'s Initializer List Constructor with user data type (5,6) (3,4) (1,2) Using Array<T>'s = Initializer List with user data type (3,4) (1,2) (5,6) Using Array<T>'s Initializer List directly with user data type (3,4) (5,6) (1,2)  Using Array<T>'s base class's operator()() to retrieve vector (3,4) (5,6) (1,2)    Using Array<T>'s data() to get the contents of its internal pointer (3,4) (5,6) (1,2)      

There are few things I’d like to know about this code: The main concerns are more towards the classes themselves than the actual code use within the main function. However, suggestions towards the use of the class are accepted as well.

  • Does this follow modern best practices? Note: I know I can encapsulate it in an namespace but for simplicity I just posted the classes themselves
    • If not what changes or fixes need to be made?
  • Is it considered readable enough?
  • Is the code efficient?
    • What can be done to improve its efficiency?
  • Are there an unforeseen bugs or gotchas that I overlooked?
  • Is this considered portable, reusable, and generic?
  • Will the derived class invoke the appropriate constructor or will it just fall back to one of them?