Q:

Tic-Tac-Toe in C++11 - follow-up 5 - final

Previous question:
Tic-Tac-Toe in C++11 - follow-up 4
How to improve this code further?
#include <iostream>
#include <cctype>
#include <algorithm>
#include <functional>
#include <array>
#include <random>
#include <ctime>

// empty struct for inheriting functionality
struct Mute
{
    Mute() = default;
    Mute(const Mute &) = delete;
    Mute(const Mute &&) = delete;
    Mute& operator = (const Mute&) = delete;
};

enum struct Player : char
{
    none    = '-',
    first   = 'X',
    second  = 'O'
};

std::ostream& operator<<(std::ostream& os, Player p)
{
    return os << static_cast<char>(p);
}

enum struct Type : int
{
    row,
    column,
    diagonal
};

template<std::size_t DIM>
class TicTacToe : public Mute
{
public:
    TicTacToe();

    bool isFull() const;
    void draw() const;
    bool isWinner(Player player) const;
    bool applyMove(Player player, std::size_t row, std::size_t column);

private:
    std::size_t mRemain = DIM * DIM;
    std::array<Player, DIM * DIM> mGrid;
};

template<int DIM>
struct Match : public Mute
{
    Match(Type t, int i) 
        : mCategory(t)
        , mNumber(i)
    {}

    bool operator() (int number) const
    {
        switch (mCategory)
        {
        case Type::row:
            return (std::abs(number / DIM) == mNumber);

        case Type::column:
            return (number % DIM == mNumber);

        case Type::diagonal:
            if (mNumber == 0)
                return ((std::abs(number / DIM) - number % DIM) == mNumber);
            if (mNumber == 1)
                return ((std::abs(number / DIM) + number % DIM) == mNumber + DIM - 2);

        default:
            return false;
        }
    }

    Type mCategory;
    int mNumber;
};

template<std::size_t DIM>
TicTacToe<DIM>::TicTacToe()
{
    mGrid.fill(Player::none);
}

template<std::size_t DIM>
bool TicTacToe<DIM>::applyMove(Player player, std::size_t row, std::size_t column)
{
    std::size_t position = row + DIM * column;

    if ((position > mGrid.size()) || (mGrid[position] != Player::none))
        return true;

    --mRemain;

    mGrid[position] = player;
    return false;
}

template<std::size_t DIM>
bool TicTacToe<DIM>::isFull() const
{
    return (mRemain == 0);
}

template<std::size_t DIM>
bool TicTacToe<DIM>::isWinner(Player player) const
{
    std::array<bool, 2 * (DIM + 1)> win;
    win.fill(true);

    int j = 0;

    for (auto i : mGrid)
    {
        int x = j++;

        for (auto k = 0; k < DIM; ++k)
        {
            if (Match<DIM>(Type::column, k)(x))
                win[k] &= i == player;

            if (Match<DIM>(Type::row, k)(x))
                win[DIM + k] &= i == player;

            if (Match<DIM>(Type::diagonal, k)(x))
            {
                if (k < 2)
                    win[2 * DIM + k] &= i == player;
            }
        }
    }

    for (auto i : win)
    {
        if (i)
            return true;
    }

    return false;
}

template<std::size_t DIM>
void TicTacToe<DIM>::draw() const
{
    std::cout << ' ';
    for (auto i = 1; i <= DIM; ++i)
        std::cout << "  " << i;

    int j = 0;
    char A = 'A';

    for (auto i : mGrid)
    {
        if (j == 0)
        {
            std::cout << "\n " << A++;
            j = DIM;
        }
        --j;

        std::cout << ' ' << i << ' ';
    }

    std::cout << "\n\n";
}

struct Random : public Mute
{
    Random(int min, int max)
        : mUniformDistribution(min, max)
    {}

    int operator()()
    {
        return mUniformDistribution(mEngine);
    }

    std::default_random_engine mEngine{ std::random_device()() };
    std::uniform_int_distribution<int> mUniformDistribution;
};

class Game : public Mute
{
public:
    void run();

private:
    void showResult() const;
    void turn();

    static const std::size_t mDim = 3;
    TicTacToe<mDim> mGame;
    std::array<Player, 2> mPlayers{ { Player::first, Player::second } };
    int mPlayer = 1;
    Random getRandom{ 0, mDim - 1 };
};

void Game::run()
{
    while (!mGame.isWinner(mPlayers[mPlayer]) && !mGame.isFull())
    {
        mPlayer ^= 1;
        mGame.draw();
        turn();
    }

    showResult();
}

void Game::showResult() const
{
    mGame.draw();

    if (mGame.isWinner(mPlayers[mPlayer]))
    {
        std::cout << "\n" << mPlayers[mPlayer] << " is the Winner!\n";
    }
    else
    {
        std::cout << "\nTie game!\n";
    }
}

void Game::turn()
{
    char row = 0;
    char column = 0;

    for (bool pending = true; pending;)
    {
        switch (mPlayers[mPlayer])
        {
        case Player::first:
            std::cout << "\n" << mPlayers[mPlayer] << ": Please play. \n";
            std::cout << "Row(1,2,3,...): ";
            std::cin >> row;
            std::cout << mPlayers[mPlayer] << ": Column(a,b,c,...): ";
            std::cin >> column;

            column = std::toupper(column) - 'A';
            row -= '1';

            pending = column < 0 || row < 0 || mGame.applyMove(mPlayers[mPlayer], row, column);
            if (pending)
                std::cout << "Invalid position.  Try again.\n";
            break;
        case Player::second:
            row = getRandom();
            column = getRandom();

            pending = mGame.applyMove(mPlayers[mPlayer], row, column);
            break;
        }
    }

    std::cout << "\n\n";
}

int main()
{
    Game game;
    game.run();
}

A:

I think the Match structure is kind of an overkill, especially since you never use it like an object, it only exists for the function call. Just use simple functions instead. 
template<int DIM>
bool MatchRow(int mNumber, int xNumber)
{
    return std::abs(xNumber/ DIM) == mNumber;
}

template<int DIM>
bool MatchColumn(int mNumber, int xNumber)
{
    return xNumber % DIM == mNumber;
}

template<int DIM>
bool MatchDiagonal(int mNumber, int xNumber)
{
    if(mNumber == 0)
    {
        return std::abs(xNumber / DIM) - xNumber % DIM == mNumber;
    }
    else if(mNumber == 1)
    {
        return std::abs(xNumber / DIM) + xNumber % DIM == mNumber + DIM - 2;
    }
    return false;
}

This also avoids the somewhat cryptic case where mNumber was not 0 or 1 and the switch passes through the case Type::diagonal to default to return false 
for (auto i : mGrid)
{
    int x = j++;

    for (auto k = 0; k < DIM; ++k)
    {
        if (MatchRow<DIM>(k, x))
        {
            win[k] &= i == player;
        }
        if (MatchColumn<DIM>(k, x))
        {
            win[DIM + k] &= i == player;
        }
        if (MatchDiagonal<DIM>(k, x))
        {   // if (k < 2) we already know k is less than 2 because MatchDiagonal returned true!!
            win[2 * DIM + k] &= i == player;
        }
    }
}

