Adding the special handling to the WaitingForFirstRollWith2Bonuses state ends up like this:

        struct WaitingForFirstRollWith2Bonuses : FirstRollUtils
        {
            State Update(int pins, int& score, int& frame) const
            {
                score += pins*2;
                if (IsStrike(pins)) {
                    ++frame;
                    if (frame == 10)
                        return LastFrameWith2Bonuses{};
                    return WaitingForFirstRollWith3Bonuses{};
                }
                return WaitingForSecondRollWith1Bonus{pins};
            }
        };

I also clean up the LastFrameWithXBonuses states, like this:

        struct LastFrameWith1Bonus
        {
            State Update(int pins, int& score, int& /*frame*/) const
            {
                score += pins; 
                return GameOver{};
            }
        };
        struct LastFrameWith2Bonuses : FirstRollUtils
        {
            State Update(int pins, int& score, int& /*frame*/) const
            {
                score += pins;
                return LastFrameWith1Bonus{};
            }
        };
        struct LastFrameWith3Bonuses : FirstRollUtils
        {
            State Update(int pins, int& score, int& /*frame*/) const
            {
                score += pins*2;
                return LastFrameWith1Bonus{};
            }
        };

Those classes don’t need to check for the number of frames or strikes or spares: they just sum in the bonus values for 1 or 2 rolls.

The WaitingForFirstRollWithXBonuses classes though do need to check for strikes and being in the last frame. Let’s write a test for the missing check for being in the 10th frame in the WaitingForFirstRollWith1Bonus state. Something like:

	{"16 gutterballs, then a spare, a strike and two bonus rolls of 1 and 2 means score is 33", []() {
		Game game;
		RollMany(game, 16, 0);
		game.Roll(5);
		game.Roll(5); // spare
		game.Roll(10); // strike
		game.Roll(1);
		game.Roll(2);
		Assert::AreEqual(33, game.Score()); // game is over here
		Assert::ExpectingException<std::invalid_argument>([&game]() { game.Roll(0); });
	}},

Get all the tests to pass and then click next.