2

Note: This is a follow-up question to this.

I have a group of template classes that do completely different things in completely different ways using completely different datatypes. They do, however, share common method names. For example, Get(), Set(), Resize(), etc. are valid methods for each of the classes in question. Additionally, they accept arguments in the same order. This allows for generalized non-friend, non-member functions to work on each of the classes. A simplified example:

template <typename Class, typename Datatype>
void Insert(const Class<Datatype>& Object, const std::size_t Index, const Datatype Value)
{
    Object.Resize(Object.Size() + 1);
    for (std::size_t CurrentIndex = Object.Size() - 1; CurrentIndex > Index; CurrentIndex--)
    {
        Object.Set(CurrentIndex, Object.Get(CurrentIndex - 1));
    }
    Object.Set(Index, Value);
}

Right now, I'm just relying on my own memory to define all the appropriate methods properly. Is there a way to have the compiler enforce the definition of the proper methods? If not, is there a better way to do this?

Community
  • 1
  • 1
Maxpm
  • 20,568
  • 29
  • 91
  • 159

4 Answers4

3

The compiler already enforces the definition of those methods by refusing to let you instantiate the template for types that don't provide the necessary methods.

Unfortunately, compilers' error messages for uninstantiable templates are often difficult to decipher.

You can document the type requirements in comments. Take a look at how the C++ standard defines type requirements like Assignable, CopyConstructible, EqualityComparable, LessThanComparable, and the requirements for types in the standard containers.

Kristopher Johnson
  • 76,675
  • 54
  • 235
  • 299
  • Sure, that results in a "method not found" error, but is there a cleaner way? – Maxpm Apr 15 '11 at 13:55
  • @Maxpm What is a cleaner way for you? – BЈовић Apr 15 '11 at 14:00
  • @Vjo Well, I don't know. That's why I asked. :P – Maxpm Apr 15 '11 at 14:02
  • 2
    I don't think there is a cleaner way to get the compiler to enforce/check the type requirements. You can document the requirements in comments. Take a look at how the C++ standard defines type requirements like Assignable, CopyConstructible, EqualityComparable, LessThanComparable, etc. – Kristopher Johnson Apr 15 '11 at 14:06
3

What you are looking for is called "concepts" and used to be a feature in C++0x but got dropped from the new standard.

There are some implementations for C++03 out there, but they are harder to use and might be not worth the trouble. e.g. Boost Concept Checking

gcc also has the --enable-concept-check option although I'm not entirely sure how that works with user code.

pmr
  • 54,366
  • 9
  • 104
  • 149
2

The compiler will enforce the correct interface by failing to compile any call to a nonexistent function; perhaps the problem is that the error messages are too cryptic?

You could define a base class which declares the required interface as non-virtual functions. The base class functions have no definitions (except where it makes sense to have an optional function with a default implementation).

Then, if the template argument derives from this base class, failure to implement a required function will cause a link error (due to attempting to call the base class functions, which are not defined). This will most likely be easier to diagnose than a typical template-related compile error.

You could go one step further and include a compile-time check that the template argument is derived from the base class; I'll leave that as an exercise for the reader. Or it might be better to just document the purpose of the base class, and leave it up to the user whether to use it or not.

Mike Seymour
  • 235,407
  • 25
  • 414
  • 617
  • 1
    +1 for the first part, but I think checking if the template argument is derived from a specific base makes the code harder to use. At least I wouldn't expect template code to behave that way. – pmr Apr 15 '11 at 14:13
  • @pmr: Yes, I'm not sure if it's a good idea either. A comment saying "Derive from this class if you want better diagnostics" is probably better than enforcement of something that's not strictly necessary. – Mike Seymour Apr 15 '11 at 14:17
0

You can use an interface.

See this question: How do you declare an interface in C++?

Community
  • 1
  • 1
Daniel A. White
  • 174,715
  • 42
  • 343
  • 413
  • An "interface" (or abstract base class) is not necessarily what he wants. He needs a particular set of function names, but the return types and other aspects of those functions may not need to all be the same. – Kristopher Johnson Apr 15 '11 at 13:51
  • I cannot use pure virtual methods because the derived classes would use arbitrary return types, and templated virtual methods will apparently make the nasal demons come after me. – Maxpm Apr 15 '11 at 13:52