It's a hard problem. Can I assume you've seen Titus Winters' talk "C++ as a Live-at-Head Language"? If not, you definitely should.
https://www.youtube.com/watch?v=tISy7EJQPzI
He discusses this exact problem: the "dreaded diamond" as applied to library dependencies. It has similar problems to the "dreaded diamond" in class inheritance: If I have two copies of library T, then whose global variables do I use?
Titus's conclusion IIRC is that there is no technical solution (especially not Python-style semver), and the only practical solution is to "live at head" and upgrade all your libraries frequently (and for all your suppliers to upgrade their libraries — e.g. in your example it's really the maintainer of library Y who's at fault, for making it impossible to use Y-trunk with T-trunk).

The (well, one) problem with Jake's idea of "version namespaces" (and the reason C++11's "inline namespaces" didn't help anything) is that namespaces apply only to names, whereas ABI affects even things which are named by the user, not the library. For example:

    struct MyClass {
        std::string s;
    };
    void foo(const MyClass&);

It doesn't matter whether `std::string` means `std::__1::string` or `std::__2::string` — once it's wrapped in `MyClass`, you've lost any benefit that name-mangling could possibly have given you. The name-mangling of `MyClass` doesn't depend on the inline namespaces of its data members (or the return types of its member functions, or anything else ABI-significant like that).

–Arthur


On Wed, Jan 22, 2020 at 8:06 AM Jake Arkinstall via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
In general this is something external to the standard, as it's more of a linking/package management issue rather than a language one.

The ideal solution would be to have version data included in name mangling. It can be done manually with version namespaces. Automating it depends on which versioning system is being used by each project, and in general becomes an ecosystem problem, with which (IMO) the standard should maintain a clear separation in order to prevent unnecessary complexity in projects that don't need such functionality.

On Wed, 22 Jan 2020, 12:56 Askar Safin via Std-Proposals, <std-proposals@lists.isocpp.org> wrote:
Hi. Consider this situation: program X depends on libraries Y and Z, Y depends on library T 1.0 and Z depends on library T 2.0. Versions T 1.0 and T 2.0 export same symbols (but they are implemented differently). As well as I understand usual C++ package managers simply refuse to build X in this situation. Can we somehow solve this problem? For example, using modules?

Askar Safin
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals