Thread: Template Hacks

  1. #1
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401

    Template Hacks

    It's good to be back in C++ land.

    I've got a frustrating set of requirements that I'm trying to fulfill. For the sake of this discussion, it boils down to two:
    1. Minimize the amount of code in the compiled product as much as possible.
    2. Minimize the amount of logic handled at run-time as much as possible i.e. maximize the amount of logic that can be completed during compile-time.
    There are numerous features that may or may not appear in the compiled product. There is a need for a function to return a bitfield with each bit set depending upon the features in the compiled product.

    So far, I've been designing as much as possible using templates since unused templates won't be included in the compiled product. I'm trying to avoid requiring a programmer to manually update the feature bitfield, since that could be a bit of a maintenance nightmare; it's all too easy to forget that you need to do it. Is there a way for a template being used at compile time to set its own feature bit in the bitfield?
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Something like this:
    Code:
    static unsigned featureField = 0;
    template <int N> struct FeatureRegisterer {
      FeatureRegisterer() { featureField |= 1 << N; }
    };
    enum Features {
      FeatureA, FeatureB, FeatureC
    };
    
    // Might or might not be instantiated.
    template <something>
    class FeatureAImpl {
      static FeatureRegisterer<FeatureA> registered_;
    };
    
    template <something>
    FeatureRegisterer<FeatureA> FeatureAImpl<something>::registered_;
    This will set the feature bits at program startup. The usual caveats regarding initialization order and DLLs apply.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    I've worked with this a few different ways without anything working. Here's what I've done so far:
    Code:
    static unsigned featureField = 0;
    template <int N> struct FeatureRegisterer {
      FeatureRegisterer() { featureField |= 1 << N; }
    };
    
    enum Features {
      FeatureA = 1, FeatureB, FeatureC
    };
    
    template <class T>
    class FeatureAImpl {
      static FeatureRegisterer<FeatureA> registered_;
    public:
      int Value() const{return 6;}
    };
    
    template <class T>
    FeatureRegisterer<FeatureA> FeatureAImpl<T>::registered_;
    
    int main()
    {
    	std::cout << "Features: " << featureField << std::endl;
    	
    	FeatureAImpl<int> featureA;
    
    	std::cout << featureA.Value() << std::endl;
    
    	std::cout << "Features: " << featureField << std::endl;
    
    	return 0;
    }
    At no point in this program does featureField ever contain a non-zero value.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Yep, my fault. If the static member isn't referenced, it isn't instantiated. Here's something that works.
    Code:
    static unsigned featureField = 0;
    template <int N> struct FeatureRegisterer {
      FeatureRegisterer() { featureField |= 1 << N; }
    };                                               
    
    enum Features {
      FeatureA = 1, FeatureB, FeatureC
    };
    
    template <Features Feat>
    class FeatureBase {
      static FeatureRegisterer<Feat> registered_;
    protected:
      FeatureBase() { (void)registered_; }
    };
    
    template <Features Feat>
    FeatureRegisterer<Feat> FeatureBase<Feat>::registered_;
    
    template <class T>
    class FeatureAImpl : private FeatureBase<FeatureA> {
    public:
      int Value() const{return 6;}
    };
    
    int main()
    {
            std::cout << "Features: " << featureField << std::endl;
    
            FeatureAImpl<int> featureA;
    
            std::cout << featureA.Value() << std::endl;
    
            std::cout << "Features: " << featureField << std::endl;
    
            return 0;
    }
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Thank you so much CornedBee. I was trying to do something very similar to that, but I couldn't seem to get it all to shake out (featureField was never updated until after construction of the objects, which wasn't what I was going for). At this point, the code still seems kind of magical to me. Would you mind explaining these points:
    • What is this line doing? I've used templates to create classes and functions, but this line really baffles me.
      Code:
      template <Features Feat>
      FeatureRegisterer<Feat> FeatureBase<Feat>::registered_;
    • The answer to this may be included in the answer to the above question, but if not, I'd better ask anyway. Like I said, every solution that I was able to come up with didn't update featureField until after construction. How does this solution work even before object construction?
    I'm pretty new to template metaprogramming, but I've got a book on the way that I'm hoping will educate me. Thanks for your patience.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    1) Compare:
    Code:
    class NonTemplate {
      static int var;
    };
    int NonTemplate::var;
    
    template <typename T>
    class Template {
      static int var;
    };
    template <typename T>
    int Template<T>::var;
    2) It doesn't. It works during object construction - namely, during dynamic construction of global-scope static objects. These are guaranteed to be initialized before the first line of main() runs, but careful: while global objects within a single translation unit (.cpp files + includes) are constructed in order of declaration, there's absolutely no rule about the order of construction in objects in different TUs. In other words, don't let any global objects rely on featureField being correctly set in their constructors. This is the infamous initialization order problem of C++.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Quote Originally Posted by CornedBee View Post
    1) Compare:
    Code:
    class NonTemplate {
      static int var;
    };
    int NonTemplate::var;
    
    template <typename T>
    class Template {
      static int var;
    };
    template <typename T>
    int Template<T>::var;
    Okay, I think I get it. It looks like the initialization of a static class member. In the case of the integer static class member, I'd usually have an = 0 on that line, but I'm guessing that the assignment is not necessary if you're initializing an object using the default constructor.

    In reading the article on static on Cprogramming.com, I came across this paragraph:
    An important detail to keep in mind when debugging or implementing a program using a static class member is that you cannot initialize the static class member inside of the class. In fact, if you decide to put your code in a header file, you cannot even initialize the static variable inside of the header file; do it in a .cpp file instead. Moreover, you are required to initialize the static class member or it will not be in scope. (The syntax is a bit weird: "type class_name::static_variable = value".)
    I'm unsure what to make of the second sentence; I've got all my templates, including the initialization line, in a header file. I'm guessing the last sentence explains why the initialization line must be included. It surprised me that I could remove the initialization line and still compile and run since the constructor of FeatureRegisterer references the static member.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  8. #8
    Registered User
    Join Date
    Nov 2008
    Posts
    30
    Quote Originally Posted by CornedBee View Post
    Code:
    static unsigned featureField = 0;
    template <int N> struct FeatureRegisterer {
      FeatureRegisterer() { featureField |= 1 << N; }
    };                                               
    
    enum Features {
      FeatureA = 1, FeatureB, FeatureC
    };
    
    template <Features Feat>
    class FeatureBase {
      static FeatureRegisterer<Feat> registered_;
    protected:
      FeatureBase() { (void)registered_; }
    };
    
    template <Features Feat>
    FeatureRegisterer<Feat> FeatureBase<Feat>::registered_;
    
    template <class T>
    class FeatureAImpl : private FeatureBase<FeatureA> {
    public:
      int Value() const{return 6;}
    };
    
    int main()
    {
            std::cout << "Features: " << featureField << std::endl;
    
            FeatureAImpl<int> featureA;
    
            std::cout << featureA.Value() << std::endl;
    
            std::cout << "Features: " << featureField << std::endl;
    
            return 0;
    }
    What exactly this template is accomplishing apart from setting the value of a global variable? C++ is already complicated enough for simple tasks sometimes.The programmer needs to specifically remember to instantiate the template anyway. So, what's the advantage?

    Code:
    enum Features {
      FeatureA = 1, FeatureB, FeatureC
    };
    
    static unsigned featureField = FeatureA | FeatureB;
    
    
    int main()
    {
            std::cout << "Features: " << featureField << std::endl;
    
            return 0;
    }

  9. #9
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Quote Originally Posted by salquestfl View Post
    What exactly is this template accomplishing apart from setting the value of a global variable? C++ is already complicated enough for simple tasks sometimes.The programmer needs to specifically remember to instantiate the template anyway. So, what's the advantage?
    This pattern will be extremely useful since it allows the programmer to program using the templates (which they'd have to do anyway) without forcing the programmer to manually update the global variable. For academic programs, program maintenance shouldn't be a problem. However, real-world programs tend to multiply in complexity quickly. Of particular concern is the "maintenance programmer" or the "update programmer": someone who has never worked in your code before but is given the task to add or change something, possibly long after you've left the company.

    Writing a program so that you can easily change it is one thing; writing a program so that someone else can easily change it is another.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  10. #10
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    It looks like this won't work consistently if features are instantiated in different transaction units.

    EDIT: unless you make featureField a proper global. Why is featureField static? If you want a seperate featureField for each transaction unit, then you need to be even more clever; what's there is not enough.
    Last edited by King Mir; 12-15-2009 at 10:27 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  11. #11
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Why is featureField static?
    Good point. I originally meant to have this hidden in a .cpp, but of course that's not possible since the changers are template instantiations.

    I'm unsure what to make of the second sentence; I've got all my templates, including the initialization line, in a header file.
    As with template functions, template static initializers must be in the header so to be found by the compiler for instantiation. The second sentence in your quote documents the non-template case.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  12. #12
    Registered User
    Join Date
    Nov 2008
    Posts
    30
    Quote Originally Posted by pianorain View Post
    This pattern will be extremely useful since it allows the programmer to program using the templates (which they'd have to do anyway) without forcing the programmer to manually update the global variable. For academic programs, program maintenance shouldn't be a problem. However, real-world programs tend to multiply in complexity quickly. Of particular concern is the "maintenance programmer" or the "update programmer": someone who has never worked in your code before but is given the task to add or change something, possibly long after you've left the company.

    Writing a program so that you can easily change it is one thing; writing a program so that someone else can easily change it is another.
    I think replacing one line

    Code:
    static unsigned featureField = FeatureA | FeatureB;
    with 15 lines involving templates is by no means easy to maintain.

  13. #13
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You're missing the point. The system as I presented it will automatically update the flags field when a feature is by some compile-time means included or excluded. Your way requires an explicit update of the flags field, which might be forgotten.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Reference Counting
    By Dae in forum C++ Programming
    Replies: 10
    Last Post: 08-13-2009, 07:34 AM
  2. Specialising a member function with a template template parameter
    By the4thamigo_uk in forum C++ Programming
    Replies: 10
    Last Post: 10-12-2007, 04:37 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. error: template with C linkage
    By michaels-r in forum C++ Programming
    Replies: 3
    Last Post: 05-17-2006, 08:11 AM
  5. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM

Tags for this Thread