title: Is it safe to use the address of a static local variable within a function template as a type identifier?
body: <p>I wish to create an alternative to <a href="http://en.cppreference.com/w/cpp/types/type_index"><code>std::type_index</code></a> that does not require <a href="https://en.wikipedia.org/wiki/Run-time_type_information">RTTI</a>:</p>
  
  <pre><code>template &lt;typename T&gt;
  int* type_id() {
      static int x;
      return &amp;x;
  }
  </code></pre>
  
  <p>Note that the address of the local variable <code>x</code> is used as the type ID, not the value of <code>x</code> itself. Also, I don't intend to use a bare pointer in reality. I've just stripped out everything not relevant to my question. See my actual <code>type_index</code> implementation <a href="http://coliru.stacked-crooked.com/a/93ef94d8be1b4c47">here</a>.</p>
  
  <p>Is this approach sound, and if so, why? If not, why not? I feel like I am on shaky ground here, so I am interested in the precise reasons why my approach will or will not work.</p>
  
  <p>A typical use case might be to register routines at run-time to handle objects of different types through a single interface:</p>
  
  <pre><code>class processor {
  public:
      template &lt;typename T, typename Handler&gt;
      void register_handler(Handler handler) {
          handlers[type_id&lt;T&gt;()] = [handler](void const* v) {
              handler(*static_cast&lt;T const*&gt;(v));
          };
      }
  
      template &lt;typename T&gt;
      void process(T const&amp; t) {
          auto it = handlers.find(type_id&lt;T&gt;());
          if (it != handlers.end()) {
              it-&gt;second(&amp;t);
          } else {
              throw std::runtime_error("handler not registered");
          }
      }
  
  private:
      std::map&lt;int*, std::function&lt;void (void const*)&gt;&gt; handlers;
  };
  </code></pre>
  
  <p>This class might be used like so:</p>
  
  <pre><code>processor p;
  
  p.register_handler&lt;int&gt;([](int const&amp; i) {
      std::cout &lt;&lt; "int: " &lt;&lt; i &lt;&lt; "\n";
  });
  p.register_handler&lt;float&gt;([](float const&amp; f) {
      std::cout &lt;&lt; "float: " &lt;&lt; f &lt;&lt; "\n";
  });
  
  try {
      p.process(42);
      p.process(3.14f);
      p.process(true);
  } catch (std::runtime_error&amp; ex) {
      std::cout &lt;&lt; "error: " &lt;&lt; ex.what() &lt;&lt; "\n";
  }
  </code></pre>
  
  <h1>Conclusion</h1>
  
  <p>Thanks to everyone for your help. I have accepted the answer from @StoryTeller as he has outlined why the solution <em>should</em> be valid according the rules of C++. However, @SergeBallesta and a number of others in the comments have pointed out that MSVC performs optimizations which come uncomfortably close to breaking this approach. If a more robust approach is needed, then a solution using <code>std::atomic</code> may be preferable, as suggested by @galinette:</p>
  
  <pre><code>std::atomic_size_t type_id_counter = 0;
  
  template &lt;typename T&gt;
  std::size_t type_id() {
      static std::size_t const x = type_id_counter++;
      return x;
  }
  </code></pre>
  
  <p>If anyone has further thoughts or information, I am still eager to hear it!</p>