#include <iostream>
#include <array>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <random>
#include <iterator>
#include <string>
class Deck;
class Card
{
public:
    enum cRanks
    {
        RANK_2,
        RANK_3,
        RANK_4,
        RANK_5,
        RANK_6,
        RANK_7,
        RANK_8,
        RANK_9,
        RANK_10,
        RANK_J,
        RANK_Q,
        RANK_K,
        RANK_A,
        MAX_RANKS,
        RANK_AIR
    };
    enum cSuits
    {
        SUIT_CLUBS,
        SUIT_DIAMONDS,
        SUIT_HEARTS,
        SUIT_SPADES,
        MAX_SUITS,
        SUIT_AIR
    };
private:
    cRanks m_rank{RANK_A};
    cSuits m_suit{SUIT_SPADES};
public:
    //Card() = default;
    Card(cRanks r, cSuits s)
        :m_rank{ r }, m_suit{ s }
    {
    }
    void print() const
    {
        char rank{};
        char suit{};
        switch (m_rank)
        {
            case(RANK_2): rank = '2'; break;
            case(RANK_3): rank = '3'; break;
            case(RANK_4): rank = '4'; break;
            case(RANK_5): rank = '5'; break;
            case(RANK_6): rank = '6'; break;
            case(RANK_7): rank = '7'; break;
            case(RANK_8): rank = '8'; break;
            case(RANK_9): rank = '9'; break;
            case(RANK_10): rank = 't'; break;
            case(RANK_J): rank = 'J'; break;
            case(RANK_Q): rank = 'Q'; break;
            case(RANK_K): rank = 'K'; break;
            case(RANK_A): rank = 'A'; break;
            case(RANK_AIR): rank = '_'; break;
            default: rank = '?';
        }
        switch (m_suit)
        {
            case(SUIT_CLUBS): suit = 'C'; break;
            case(SUIT_DIAMONDS): suit = 'D'; break;
            case(SUIT_HEARTS): suit = 'H'; break;
            case(SUIT_SPADES): suit = 'S'; break;
            case(SUIT_AIR): suit = '_'; break;
            default: suit = '?';
        }
        std::cout << rank << suit << ' ';
    }
    friend Deck; 
};
class Deck
{
public:
    using array_type = std::array<Card, 52>;
    using index_type = int;
private:
    array_type m_deck;
    index_type m_index{ 0 };
public:
    Deck()
    {
        m_index = 0;
        int index{0};
        for (int s{ 0 }; s < Card::MAX_SUITS; ++s)
        {
            for (int r{ 0 }; r < Card::MAX_RANKS; ++r)
            {
                m_deck[index].m_rank = static_cast<Card::cRanks>(r);
                m_deck[index].m_suit = static_cast<Card::cSuits>(s);
                index++;
            }
        }
    }
    void print()
    {
        if (m_index > static_cast<int>(m_deck.size()) - 1)
        {
            std::cout << "\nDeck out of cards!";
            return;
        }
        std::cout << '\n';
        for (int i{ m_index }; i < m_deck.size(); ++i)
            m_deck[i].print();
    }
    void shuffle(unsigned int seed = 777)
    {
        std::mt19937 g{ seed };
        std::shuffle(m_deck.begin(), m_deck.end(), g);
    }
    const Card& draw()
    {
        if (m_index > static_cast<int>(m_deck.size()) - 1)
        {
            std::cout << "\nDeck out of cards!";
            return Card(Card::RANK_AIR, Card::SUIT_AIR);
        }
        return m_deck[m_index++];
    }
};
int main()
{
    Deck deck{};
    deck.print();
    deck.shuffle();
    deck.print();
    return 0;
}
Simple BlackJack game-exercise to learn OOP. In the above code I get the error message "the default constructor of cannot be referenced -- it is a deleted function" on my Deck constructor. Is it wise to assume that my m_deck array cannot be instantiated so that the constructor of Deck can assign values to it because the Card class has no default constructor? What if I want my default Card constructor to have arguments? Can I avoid using "Cards() = default;" in my Cards class? I was thinking that it is only sensible to instantiate a Card object only if you define it's nature (rank and suit).
 
    