关于std::type_info::before与实现排序规则的技术问询
Alright, let's break down std::type_info::before—what its sorting rules mean for specific types, and how it impacts your user-defined classes. I'll keep this practical, since that's what matters most when writing code.
std::type_info::before Actually Does First, let's get clear on the core behavior: this member function lets you compare two std::type_info objects to establish a stable, implementation-defined ordering. The C++ standard doesn't dictate how this order is determined—compilers (GCC, Clang, MSVC, etc.) can use any logic they want, as long as three rules hold:
- For two distinct types,
a.before(b)will always return the same boolean result (no flips between runs of the same program). - If
a.before(b)istrue, thenb.before(a)must befalse(asymmetry). - If
a.before(b)andb.before(c)are bothtrue, thena.before(c)must also betrue(transitivity).
Common implementation strategies include hashing the type's mangled name, using the memory address of the type's metadata, or even the order in which types are first encountered during compilation. But you never get to see or control that logic.
For built-in types (like int, float, char, or pointers), the ordering is fixed for a given compiler and version, but completely unportable. For example:
- In GCC,
typeid(int).before(typeid(float))might returntrue. - In MSVC, the same comparison could return
false.
The only safe way to use this ordering for built-in types is as a stable sorting key—like storing std::type_info pointers in a std::set, or using them to group types in a collection. You can never rely on the order to mean anything about the types themselves (e.g., you can't assume "earlier" types are smaller, or have simpler layouts).
Now for the part you care about: your own classes and structs. Here's what you need to know:
- Each unique type gets a unique, stable order: If you define
class Fooandclass Bar,typeid(Foo).before(typeid(Bar))will always return the same value for your program. This holds even for template instantiations (e.g.,typeid(std::vector<int>).before(typeid(std::vector<std::string>))is a stable comparison). - You can't control the order: There's no way to force
Footo come beforeBar—the compiler decides this, and it might depend on things like where you declared the types in your codebase, or how the compiler's metadata is stored. - Practical use cases: The most common use is building type-safe generic containers or type mappings. For example, if you want a registry that associates types with factory functions, you can use
std::type_index(a wrapper aroundstd::type_infothat usesbeforefor comparisons) as the key in astd::map:#include <typeinfo> #include <typeindex> #include <map> #include <functional> #include <memory> class Base {}; class Derived1 : public Base {}; class Derived2 : public Base {}; std::map<std::type_index, std::function<std::unique_ptr<Base>()>> factory_map; int main() { factory_map[typeid(Derived1)] = []() { return std::make_unique<Derived1>(); }; factory_map[typeid(Derived2)] = []() { return std::make_unique<Derived2>(); }; // This works because std::type_index uses before to order keys auto derived1 = factory_map[typeid(Derived1)](); } - Critical caveat: Never use
beforeto infer type relationships. Just becausetypeid(Base).before(typeid(Derived))istruedoesn't meanBaseis a parent class ofDerived—the order has nothing to do with inheritance, type size, or name similarity. It's purely a stable, arbitrary ordering.
std::type_info::beforegives you a stable but arbitrary way to order types, defined by your compiler.- For built-in types, don't rely on the order across compilers or versions.
- For user-defined types, it's great for building type-safe collections/mappings, but you can't control or interpret the order beyond stability.
内容的提问来源于stack exchange,提问作者user9196120

