I was looking at the documentation. Far as I can tell, a sprite has a pointer to its texture, which in this case would be the tilesheet. I assume you declare this once somewhere, not per render, in which case all is well. I assume you would use one sprite as it sees you are suggesting, so that leaves only the IntRect's. As far as I can tell, though, you only need one IntRect per tile TYPE. For example, say you have two tiles, GRASS and WATER. So you would need two IntRect dictating where in the tilesheet the tile's texture is. I assume you would also declare this beforehand and not every render.
When rendering, then - and in whatever render function/thread/etc have you, the tilesheet and IntRects need to be in scope - you can declare a sprite - or just use one potentially declared before like the above - and set its texture as the tilesheet. (so perhaps having the sprite declared beforehand would be good). Then, by case, set the correct texture rect and position (you could have the grass tile, but you also need to draw it where the tile is on the screen), and draw it.
Note that I have not tested this myself. As far as I can tell, you do not need 45 IntRects per tile type, and I don't think this is to bad optimization wise, although this approach takes a toll on memory.
I don't think you would need more than one IntRect per tile, as your tilesheet should never change at runtime.
Edit after comment:
Your right, that would be a problem. I don't think there is a way around it unless you don't move the other tiles and make them independant of each other (leaving empty space). Although, assuming your tilesheet is perfect, you might be able to hold the IntRects in an array, which is created whilest looping. (you could then have an Enum which dictates which index is which).
As per declaring IntRects... the setTextureRect argument needs one, thus you need at least one. But somewhere, perhaps as defined/constant/magic numbers, but that is not very efficient either. Perhaps, though, you could... automate the process. Say, your tilesheet is x tiles by y tiles. You make an enumerated value for each tile. You can set IntRects either beforehand or at render (probably not to fast the latter way). Since you know how many tiles wide and high it is (given the texture and tilesize you can calculate this at runtime so changes don't break it), you can go from left to right, and upon grabbing the last tile, drop down a row, and so on. For each one, you fill an IntRect,, hopefully in an array of IntRects, with the coordinates of that texture.
Now, you would need an enum, with the tile values, like WATER, GRASS etc. Put them in the order the algorithm would fetch them - say, if it looks like this:
WATER, GRASS, SAND,
ROCK, ICE, SOMETHING
then the enum is like:
Note that last one is optional, but it allows you to know how many tiles you have (assuming you don't modify it and it goes sequentially starting from 0), which might be useful.
Then, to access the according texture for a tile, you could go, say, intRects[WATER], and then it would access the water tile. Assuming you change the tilesheet, making sure to leave no enclosed holes, then you can simply change the order of enums. This is also where NUM_TILES can come in handy, if you have an unfinished row for instance, so you can still collect it correctly. Assuming that works (this is speculation), I think this is decent from a maintenance. Worst part is adjusting the tilesheet, but once you have done that the worst is over, in theory.