Question: I'm compiling the following program using Microsoft Visual C++, as a C++20 program:

```
#include <iostream>
#include <tuple>

int main()
{
    auto t1 = std::make_tuple("one", "two", "three");
    auto t2 = std::make_tuple("one", "two", "three");

    std::cout << "(t1 == t2) is " << std::boolalpha << (t1 == t2) << "\n";
    std::cout << "(t1 != t2) is " << std::boolalpha << (t1 != t2) << "\n";

    return 0;
}

```

When I run it, I see the following output:

```
(t1 == t2) is false
(t1 != t2) is true

```

The tuples are identical, so why does it have wrong comparison results? How do I fix this?

Answer: 
The problem is unrelated to C++20, but comes from how string literals are implemented. The answer is for example here:

[Why do (only) some compilers use the same address for identical string literals?](https://stackoverflow.com/questions/52814457/why-do-only-some-compilers-use-the-same-address-for-identical-string-literals)

In short, your program falls into the category of "~~undefined~~ unspecified behavior", as it assumes that identical C-style string literals have identical addresses. This is because expressions like `"a" == "a"` compare addresses, not the content. Your code could be made safe and predictable if you used `std::string` literals, like `"one"s`, `"one"sv` etc., see <https://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s>
`auto` is not always your friend. I would argue the proper way to get reliably the “right” behaviour without boilerplate is to explicitly use a type that you know has value-equality. Then you can also omit the `make_tuple` and simply use the initialiser-list constructor:

```
#include <string>
#include <tuple>
#include <iostream>

typedef std::tuple<std::string, std::string, std::string> StrTriple;

int main() {

  StrTriple t1{"one", "two", "three"};
  StrTriple t2{"one", "two", "three"};

  std::cout << "(t1 == t2) is " << std::boolalpha << (t1 == t2) << "\n";
  std::cout << "(t1 != t2) is " << std::boolalpha << (t1 != t2) << "\n";

    return 0;
}

```

No doubt some would argue that the memory management of `std::string` incurs unnecessary overhead. `string_view` *may* be preferrable, however chances are in a real-world application the strings will need to be dynamically allocated anyway somewhere.