Maybe this is how it's typically done. You have your list of different tiles that represent a road tiles in all their possible orientations. Left to right, all four corners, top to bottom, whatever. Now you'll index all those tiles with a byte each. 8 bits, one for each direction. This could be in a hashmap or by file name... however you want to do this.
So you have this:
The byte code for the above tile is 00000000. Then your tile that goes from left to right (or right to left) is like this:
The byte code for that tile is 10001000, or 136. As another example, lets look at a three way intersection:
The byte code for that tile is 10101000.
You probably see where I'm going. You set bit positions in the byte representing connections. This is far better than trying to do some big if/else chain that I've seen before. When you're looking to place a tile, examine the tiles around it and create a byte along the way. Set 1's for tiles that have roads (or whatever you're looking to connect) and 0's for tiles that don't. When you're done, you'll have the byte code for the exact tile you need.
Note that when creating the assets you can reuse a lot of them by simply rotating and assigning the correct byte code to it.
Updated images to be less crappy. Yes those are better than before.