What I do:
First I create an image in which 1 pixel represents 1 tile and in which each color in the image represents a tile texture (green pixel = grass texture, gray pixel = road texture, etc.). Such a landscape image can even be easily edited in every graphics program.
In addition I do have images with the ground textures itself of course. Those I load at program start and even create one sprite for each texture image. I use an enum to define the different texture types (TEXTURE_GRASS, TEXTURE_ROAD, etc.). For simplicity you might use a std::map<TextureTypeEnum, sf::Sprite> for that.
Then I load the landscape image and store it one in a simple 2D matrix, a custom class which has functions like loadFromLandscapeImage(const std::string& FileName) and getTextureType(int x, int y). Internally it is a simple 1D std::vector (index in vector = landscape image width * y + x; but care for boundaries!). Of course the vector already includes the texture type, based on the color code in the landscape image.
Each frame I calculate which tiles are visible (based on scrolling and zooming and window size and stuff) and afterwards calculate the width and height all the texture sprites must have (in pixel size). In case my current sprites don't have that width and height yet (and only in that case) I loop over all sprites of the textures and set their sprite scale according to the required width and height.
Then I loop over the visible tiles, call getTextureType(x, y), access the according sprite based on the texture type and finally render that sprite on the appropriate position on the screen.
After the landscape is drawn and I now loop over the visible creatures and other stuff to draw them.