Use pairs for exactly two values, especially in standard library contexts like maps or simple coordinates. Use tuples when you have three or more values and don't want to define a struct.
Both work for one-off return values. Structs win when your data has clear semantic meaning or when you'll reuse the type. A Student struct with named fields beats tuple<string, int, double> because s.name is clearer than get<0>(s).
Tuples suit temporary groupings where defining a struct feels heavy. If you find yourself passing the same tuple type through many functions, convert it to a struct for readability.