Question

In C# we can define a generic type that imposes constraints on the types that can be used as the generic parameter. The following example illustrates the usage of generic constraints:

interface IFoo
{
}


class Foo<T> where T : IFoo
{
}

class Bar : IFoo
{
}

class Simpson
{
}

class Program
{
    static void Main(string[] args)
    {
        Foo<Bar> a = new Foo<Bar>();
        Foo<Simpson> b = new Foo<Simpson>(); // error CS0309
    }
}

Is there a way we can impose constraints for template parameters in C++.


C++0x has native support for this but I am talking about current standard C++.

Was it helpful?

Solution

As someone else has mentioned, C++0x is getting this built into the language. Until then, I'd recommend Bjarne Stroustrup's suggestions for template constraints.

Edit: Boost also has an alternative of its own.

Edit2: Looks like concepts have been removed from C++0x.

OTHER TIPS

If you use C++11, you can use static_assert with std::is_base_of for this purpose.

For example,

#include <type_traits>

template<typename T>
class YourClass {

    YourClass() {
        // Compile-time check
        static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");

        // ...
    }
}

"Implicitly" is the correct answer. Templates effectively create a "duck typing" scenario, due to the way in which they are compiled. You can call any functions you want upon a template-typed value, and the only instantiations that will be accepted are those for which that method is defined. For example:

template <class T>
int compute_length(T *value)
{
    return value->length();
}

We can call this method on a pointer to any type which declares the length() method to return an int. Thusly:

string s = "test";
vector<int> vec;
int i = 0;

compute_length(&s);
compute_length(&vec);

...but not on a pointer to a type which does not declare length():

compute_length(&i);

This third example will not compile.

This works because C++ compiles a new version of the templatized function (or class) for each instantiation. As it performs that compilation, it makes a direct, almost macro-like substitution of the template instantiation into the code prior to type-checking. If everything still works with that template, then compilation proceeds and we eventually arrive at a result. If anything fails (like int* not declaring length()), then we get the dreaded six page template compile-time error.

You can put a guard type on IFoo that does nothing, make sure it's there on T in Foo:

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}

Check out Boost

The Boost Concept Check Library (BCCL)

The Concept Check library allows one to add explicit statement and checking of concepts in the style of the proposed C++ language extension.

Sort of. If you static_cast to an IFoo*, then it will be impossible to instantiate the template unless the caller passes a class that can be assigned to an IFoo *.

Only implicitly.
Any method you use in a method that is actually called is imposed on the template parameter.

You can do it. Create the base template. Make it have only Private constructors. Then create specializations for each case you want to allow (or make the opposite if the disallowed list is much smaller than the allowed list).

The compiler will not allow you to instantiate the templates that use the version with private constructors.

This example only allow instantiation with int and float.

template<class t> class FOO { private: FOO(){}};

template<> class FOO<int>{public: FOO(){}};

template<> class FOO<float>{public: FOO(){}};

Its not a short and elegant way of doing it, but its possible.

Look at the CRTP pattern (Curiously Recursive Template Pattern). It is designed to help support static inheritence.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top