Your thoughts on non-type template parameters

6837d514b487de395be51432d9cdd078
0
TheNut 179 Jan 25, 2012 at 17:46 c++

I am implementing an observable property class used for data binding purposes similar to data binding available in WPF. Before I move on, let me show you a quick code snippet of this property class.

// Note, for brevity purposes the notification logic was stripped
template<class T, const String &Name>
class Property
{
     private:
          T mValue;

     public:
          Property () {}
          Property (const T &value) { mValue = value; }
          Property (const Property<T, Name> &value) { *this = value; }
          virtual ~Property () {}

          virtual T & operator = (const T &value) { mValue = value; return mValue; }
          virtual Property<T, Name> & operator = (const Property<T, Name> &value) { mValue = value.mValue; return *this; }

          operator T () const { return mValue; }

          const String &GetName () const { return Name; }
};

// Example code using the above property class

extern const String MyPropertyName = "MyProperty";
int main (int argc, char **argv)
{
     Property<int, MyPropertyName> MyProperty;
     MyProperty = 100;
     printf("%d\n", (int)MyProperty);

     return 0;
}

As you can see, a simple class with a template type can sufficiently handle properties; however I also need to include the property name with the property object. As you can see I am using a non-type template parameter to pass in the property name. I thought about passing the name as a parameter in the constructor, but it would add an extra step. I’m trying to minimize the amount of boilerplate coding, but at the same time I don’t want to sway towards “bad programming” practices. I never had a need to use non-type template parameters before and so I’m cautious about swaying in that direction. I’d like to hear your feedback on this and whether or not you think it could be done better / differently, but still try to minimize bloat. When you have to create hundreds of properties and deal with bindings, it can become a maintenance nightmare.

4 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Jan 25, 2012 at 18:18

Hmm. I’m skeptical. The issue with doing it this way is you generate a new copy of the code for Property for each name you use. That may not be a big deal since the Property class looks like all the methods will probably get inlined. But, for instance, you can’t write a function that works on all int properties. Well, you can by templatizing it on the name, but then you’ll get a new copy of that function for each name, so you get a bunch of code bloat. Nor can you make an array of properties, or even just int properties, unless they all have the same name. On the other hand, having the name be a field in the Property class would increase the data size, while having it be a template parameter means these references are resolved at compile time and never stored at runtime. On balance I’d probably lean toward having the name be a field, personally. The difficulties in writing generic functions that work on many properties tip the balance for me.

6837d514b487de395be51432d9cdd078
0
TheNut 179 Jan 25, 2012 at 20:32

Yeah, I jumped the gun here. Looks like I’ll stick to the field / constructor approach as that’s what I am really aiming for (runtime checks vs compile time). A little more typing, but oh well.

6eaf0e08fe36b2c23ca096562dd7a8b7
0
__________Smile_ 101 Jan 26, 2012 at 10:17

I think approach with non-type parameters is quite good except one thing: virtual functions add additional pointer field into Property class and spawn virtual table and function bodies for every property name. If you really need virtual functionality, you can achieve similar effect with templates:

template<typename D> class Base
{
    int virtual_function()
    {
        return static_cast<D *>(this)->virtual_function();
    }
};

class Derived : public Base<Derived>
{
    int virtual_function()
    {
        return 1234;
    }
};

template<typename D> int run_virtual_function(Base<D> *ptr)
{
    return ptr->virtual_function();
}
340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 Jan 27, 2012 at 11:52

That still has the requirement that *all* functions that need to handle your types in a generic way are templatized.

Of course, there simply is a middle ground

template<class T> class IProperty
{
public:
    virtual const String & GetName() const = 0;
};

template<class T, const String & S> class Property : public IProperty<T>
{
public:
    const String & GetName() const { return S; }
};