Hi! I also encountered this problem before and I'll tell you this is the most interesting thing to do before you do anything in game development. I have implemented birds-eye tilemap and its quite fun.
What I have done is very expensive and not elegant at all. If you are familiar with data structures it can do you good.
For instance, what I have done on mine is to create a class called Tile which contains attributes of that tile. I have attribute of those tile written on a text file and I have written a simple interpreter to read those attributes and plug that on the tile. It can be done in many ways and I prefer it to do on my own terms so I know it in every bolt though you can use different techniques like using XML. I saw a third-party of tileset maker using that as well. But I didn't use similar methodologies because I have to learn how to parse XML file, so I parse my own file on my own rules of parsing.
So I have class Tile being manage on 2d vector inside a wrapper class Tileset. This way you can make it very easy to save the tileset onto a text file and load it to later use. You must understand that the tileset is for information and visual purposes only so you might want to write a separate class to represent that data of tile( If in case you want to do Path Finding with variable terrain cost, penalties etc).
My Tileset loads a text file containing the tiles contained in the tileset including their positions and name on this form:
grass 0 , 0
grass 32 , 32
...
It is very simple, grass is the name of the tile in the asset library, asset library throws to me the texture which has been loaded before, and set that into position. I can tell you my asset manager is completely stringified! But I get what I wanted, I am able to call resources on demand by just calling their callsigns including their attributes and plug them to the entity! Though its complex but its a good thing if you have resource loader to load resources for your tilemap.
Yet again, that is very expensive when you read it line by line but I choose to do this way so I can understand the mechanism(risking myself in isolation). I always prefer to do it your own way so when you encounter some design problems and able to fix it and did a some mistake jot it down and never do it again. By then you learn.
I am making an RTS game for my school research and yes I use a grid editor because it is really hard to hardcode the tileset base on how I have coded it on my RTS framework. So I make class name GridEditor and grid editor requires tileset before it is created. GridEditor will provide editing for you. It is similar to String being pass on StringBuffer for editing in Java and I use the same concept. Albeit the fact that in my code I haven't done the Attorney-Client pattern because Tileset is clearly exposed for editing( Not requiring GridEditor anymore). But as you can see, you can really learn a lot and also learn base on the decision you've made. So don't get distracted, just do what you think is best to do. It's all yours anyway, making personal projects like this it not just about coding its also about decision making and its good quality that you always made good and sound judgment implementing your design.
I never used any external libraries to implement this framework for the RTS I am writing but SFML itself. Less dependencies the better(for me), because you can understand it more(because you made it) though its very bad to reinvent the wheel, but sometimes that is want you need to get the job done and that's what matters.
Just do optimization/refactoring/design rehabilitation when you have a working prototype of your own tileset.
And I learn once again, why the heck did I name my class Tileset where in fact it should be named Tilemap? Oh well...
Cheers
-Neon Warge