In Java you can restrict generics so that the parameter type is only a subclass of a particular class. This allows the generics to know the available functions on the type.
I haven't seen this in C++ with templates. So is there a way to restrict the template type and if not, how does the intellisense know which methods are available for <typename T>
and whether your passed-in type will work for the templated function?
Use the
static_assert
withstd::is_base_of
Java generics and C++ templates are completely different things, the best thing you can do is avoiding attempting a 1-to-1 mapping. That being said, the question still remains valid, and the answer is not simple.
The simple approach used in most places is that the requirements on the type are part of the contract on the template. For example,
std::sort
requires that the first two arguments behave as RandomAccessIterators which is a documentation only interface (the properties are described, but there is no mechanism in code for this). Then the template just uses that information.The second simplest approach would be to document that contract and provide
static_assert
s that verify what can be verified.The next available step is to use SFINAE, which is a technique in which you force the compiler to check some features of the types that are being substituted. If the substitution (and check) fails, the template is dropped as invalid and the compiler moves on. I personally discourage most uses of SFINAE, it is a great tool, but it is often misused.
In a future standard there will be higher level constructs to enforce some form of an interface on the arguments to templates by means of Concepts. The problem is that it has proven to be hard to define how those constraints are to be defined, detected or verified and until a good solution is found the standard committee won't settle for a knowingly bad approach.
All that being said, I might want to refer back to the first paragraph here. There is a huge difference between Java generics and C++ templates. The latter provides something that is called compile time polymorphism. No real interface type is defined anywhere in the program there are [in general] no constraints that the types used in a template are related in any possible way.
The way you'd do this in C++ would be to only use the template type in the input and output interfaces of your class.
This is somewhat analogous to what Java does under the hood, if I understand their Generics properly: the
Derived
version is merely a thin wrapper around theBase
version that does type casting on input/output operations.C++
template
s are much more than this. The entire class is written anew for each new set of type arguments, and the implementations can, in theory, be completely different. There is no relationship between astd::vector<int>
and astd::vector<long>
-- they are unrelatedclass
es -- except that they can both be pattern-matched asstd::vector
s, and they share many properties.This level of power is only rarely needed. But for an example of how it can be extremely powerful, most standard libraries use it to create type-erasure objects in
std::function
.std::function
can take any language element for whichoperator()
is defined and compatible with its signature, regardless of the run-time layout or design of the type, and erase (hide) the fact that its type is distinct.So a function pointer, a lambda, a functor written by some programmer in tibet -- despite having no run time layout compatibilities, a
std::function< bool() >
can store all of them.It (typically) does this by creating a custom holder object for each type
T
that has its own copy, move, construct, destruct and call code. Each of those is custom-compiled for the type in question. It then stores a copy of the object within itself, and exposes avirtual
interface to each of these operations.std::function
then holds a pointer to the parent interface of that custom object holder, and then exposes its "value-like" interface to the end user (you).This mixture of
pImpl
andtemplate
duck type code generation andtemplate
constructors is known as type-erasure in C++, and it allows C++ to not have the common "object" root (with the entailed restrictions on run time object layout) that Java has without much in the way of sacrifice.In C++, if you have some template argument
T
, then it is effectively constrained to be one of some set of classes by virtue of how it is used. For instance if you refer toT::foo
somewhere in the template expansion, thenT
cannot possibly be a class which does not have afoo
member. Or supposeT::foo
does exist, but has the wrong type; your template does something likeT::foo + 1
, but theT::foo
which is there is not arithmetic.If
T
satisfies the template in every way, and the resulting instantiation makes sense, there is no reason to worry about it.It is an important flexibility in C++ to be able to use a template with classes that are not related in any way (i.e. by inheritance).
Someone who needs to use the template just has to write a class whose structural features match the requirements of the template; the user of the template doesn't have to derive from certain types just to use them as arguments.
The only benefit to this kind of constraint would be clearer diagnosis. Rather than getting an error message about
T::foo
being inappropriate in some way, you might get "typeWidget
does not match parameter 2 of templateXyz
."However, though clearer, the diagnostic comes at the price of accepting the philosophy that this mismatch is in fact the real problem. (What if the programmer can just fix the
foo
member and make it work?)As of C++11, there is no way to constrain template type arguments. You can, however, make use of SFINAE to ensure that a template is only instantiated for particular types. See the examples for
std::enable_if
. You will want to use it withstd::is_base_of
.To enable a function for particular derived classes, for example, you could do:
The C++ working group (in particular, Study Group 8) are currently attempting to add concepts and constraints to the language. This would allow you to specify requirements for a template type argument. See the latest Concepts Lite proposal. As Casey mentioned in a comment, Concepts Lite will be released as a Technical Specification around the same time as C++14.
Just be specific