Restricting the type to instantiate template class

 

Precaution: Basic knowledge on C++ templates needed

Recently, once of my friend, Amal asked me to share if I know any methods to restrict the types to instantiate a template class. Which means that, suppose, if you have written some classes to support only floating types like double, float etc… and want to other types like, int, long or any other types. Or if you support a certain kind of data, it will affect the core logic used in that, in that case you may have to restrict the data type for you class.

Amal described his idea. It goes as follows. (I’ve modified the code a bit make it comfortable for me J. You can see the original post in his blog)

template <class T>

class CTest

{

      void AssertType( float& f ) const{ } // Allow Type double

      // If you want to add more, add with the same signature

public:

      CTest()

      {

          // Here goes the compilation error   

           T validate;

           AssertType( validate );

      };

};

 

int main(int argc, char *argv[])

{

    CTest<float> t;

    CTest<int> er; // Error: Invalid Type

    return 0;

}

 

When we discussed about this, I got an idea using template specialization. The disadvantage of my method is that, it will not show any kind of compilation error, but linking error. In method one, we have additional cost of instantiating a temporary object for type checking. If the classes design to support primitive data types, no needs to worry, it will not cost any kind of performance overhead. Trust me J. Both methods will support inheritance of the data types.

 

Anyway let me introduce my method.

template <class T>

class CTest

{

      public:

      CTest();

};

 

template <> CTest<double>::CTest()

{

         cout << “Test”;

}

 

int main(int argc, char *argv[])

{

    CTest<int> t;

    return 0;

}

The above method is implemented using template specialization. The ctors are allowed only for allowed type. Basicsally both methods are doing the same thing but in different way. If you use the second method you can avoid a temporary object to assert the type data it’s going to support.

 

There’s one more disadvantage for all of the above method, suppose your want to support both float and double, you will have to specialize ctors with both float and double(using method 2) and two overloaded functions AssertType function is needed.

 

Ok let me do some more far thinking to support compatible types without writing additional code. I think it’s better to take method 1 for modification.

     void AssertType( const double& f ) const{ } // Allow Type double

What if you put a const in front of the parameter? What would happen? Now the compiler will support both double and float. Or in other words, it will try to type case the type we passing to the class to call the AssertType function. But alas!!! It will also support int type with a warning. So not always we can achieve the conversion using this method because of compiler will automatically convert between types. One more thing all the above methods support Inherted types. i.e If you allow base class type, surely it will also support derived class type also J

 

What you guys think? Is there any better Idea? Please share with me if possible.

 

[I am using Calibri and Consolas Font for blogging: for better viewing, download it from Microsoft website]

 
  • Todd Greer

    Here’s the simplest way I can think of:

    #include
    #include

    template
    class CTest
    {
    BOOST_STATIC_ASSERT(boost::is_integral::value);
    };

    That will fail to compile exactly if T is an integral type. If you only wish to exclude a particular type, such as int, a simpler approach is:

    template
    class CTest
    {};

    template
    class CTest; // no definition of specialized class.

    Neither approach has any runtime or size overhead. The boost static assertion will give somewhat more clear error messages. BTW, you may find it useful to use static assertions even when the illegal type would already trigger a compilation failure. This technique lets you give the user a reasonably clear error, rather than one that might be buried several layers deep.

    See http://boost.org/doc/libs/1_35_0/doc/html/boost_staticassert.html and http://boost.org/doc/libs/1_35_0/libs/type_traits/doc/html/index.html for more info.

    Also, the best book on this topic is probably _C++ Template Metaprogramming_ by David Abrahams and Aleksey Gurtovoy. I highly recommend it.