Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Answer One</strong></p> <p>The general technique of deriving a class like this is the <a href="http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern" rel="noreferrer">Curiously Recurring Template Pattern (CRTP)</a>:</p> <pre><code>class PingMessage: public MessageTmpl &lt; 10, PingMessage &gt; </code></pre> <p>Your specific technique of using a template class's static member initialization to register subclasses of that class is (IMO) simply brilliant, and I've never seen that before. A more common approach, used by unit test frameworks like <a href="http://unittest-cpp.sourceforge.net/" rel="noreferrer">UnitTest++</a> and <a href="http://code.google.com/p/googletest/" rel="noreferrer">Google Test</a>, is to provide macros that declare both a class and a separate static variable initializing that class.</p> <p><strong>Answer Two</strong></p> <p>Static variables are initialized in the order listed. If you move your m_List declaration before your MessageFactory::Register calls, you should be safe. Also keep in mind that if you start declaring Message subclasses in more than one file, you'll have to wrap m_List as a singleton and check that it's initialized before each use, due to the <a href="http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12" rel="noreferrer">C++ static initialization order fiasco</a>.</p> <p><strong>Answer Three</strong></p> <p>C++ compilers will only instantiate template members that are actually used. Static members of template classes is not an area of C++ that I've used much, so I could be wrong here, but it looks like providing the constructor is enough to make the compiler think that MESSAGE_ID is used (thus ensuring that MessageFactory::Register is called).</p> <p>This seems very unintuitive to me, so it may be a compiler bug. (I was testing this in g++ 4.3.2; I'm curious to know how Comeau C++, for example, handles it.)</p> <p>Explicitly instantiating MESSAGE_ID also suffices, at least in g++ 4.3.2:</p> <pre><code>template const uint16_t PingMessage::MESSAGE_ID; </code></pre> <p>But that's even more unnecessary work than providing an empty default constructor.</p> <p>I can't think of a good solution using your current approach; I'd personally be tempted to switch to a technique (such as macros or using a script to generate part of your source files) that relied less on advanced C++. (A script would have the added advantage of easing maintenance of MESSAGE_IDs.)</p> <p><strong>In response to your comments:</strong></p> <p>Singletons are <i>generally</i> to be avoided because they're often overused as poorly disguised global variables. There are a few times, however, when you really do need a global variable, and a global registry of available Message subclasses is one of those times.</p> <p>Yes, the code that you provided is initializing MESSAGE_ID, but I was talking about <a href="http://msdn.microsoft.com/en-us/library/by56e477%28VS.80%29.aspx" rel="noreferrer">explicitly instantiating</a> each subclass's instance of MESSAGE_ID. Explicit instantiation refers to instructing the compiler to instantiate a template even if it thinks that that template instance won't otherwise be used.</p> <p>I suspect that the static function with the volatile assignment is there to trick or force the compiler into generating the MESSAGE_ID assignment (to get around the problems that dash-tom-bang and I pointed out with the compiler or linker dropping or not instantiating the assignment).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload