Concept mapping unconstrained templates

Authors:Ville Voutilainen <ville.voutilainen@gmail.com> and Daniel Krügler <daniel.kruegler@googlemail.com>
Number:N2919=09-0109
Date:2009-07-23

Abstract

This paper explains why it's important to be able to write concept map templates for unconstrained templates. The cases this paper is concerned with are cases where syntax adaptation is necessary. This paper is meant as supplemental material for Core Issue 911. Since concepts have been dropped from C++0x, the issue is perhaps not of high priority, but we want to record this paper so that the issue is not forgotten, should there be a redesign of concepts.

The Problem

Currently, it's not possible to write concept map templates for unconstrained templates. The restriction as of N2914 is

14.11 [temp.constrained], paragraph 5

"Within a constrained context, a program shall not require a template
specialization of an unconstrained
template for which the template arguments of the specialization depend
on a template parameter."

The problem elaborated

There are many existing unconstrained templates that users will want to use with concepts. Practical examples for the previous Range concept are Qt containers (like QList) and Symbian containers (like RPointerArrays). The former usually do not require syntax adaptation (and could thus be mapped with empty concept map templates) for Range (or even Container), whereas the latter do. For the short-term foreseeable future, these container templates will remain unconstrained.

In addition to Range, there are other standard concepts that are likely targets for early user adaptation, like the Container concepts. These, too, cannot be currently mapped to from unconstrained templates.

When constrained template libraries become available, the same adaptation problem arises for them - existing unconstrained templates cannot be adapted to be used with the constrained templates by concept map templates.

Given the amount of existing unconstrained template code, we state that it's absolutely crucial to be able to map such templates to concepts. Even after a redesign of concepts, we state that it's paramount to provide a migration path to existing code, without suggesting that existing code has to be constrained before it can be used with concepts.

Code example

The code example we wrote was written for concepts as proposed to inclusion for C++0x. We decided to keep the example in this paper, because it illustrates the problem.

There's a class in Qt that is a likely candidate for mapping to InputIterator, the class in question is QDictIterator. It's defined roughly as follows:

template<class type>
class QDictIterator : public QGDictIterator
{
 ...
  type* operator*();
  type* operator++();
  type* current() const;
};

In order to map it, we would like to write something like the following:

template<ObjectType T>
concept_map InputIterator<QDictIterator<T>> {
 typedef T value_type;
 typedef T& reference;
 typedef T* pointer;
 ...
 reference operator*(QDictIterator<T>& it) { return *it.current(); }
 QDictIterator<T>& operator++(QDictIterator<T>& it) { ++it; return it; }
 pointer operator->(const QDictIterator<T>& it) { return it.current(); }
 ...
}

This concept map is forbidden under the existing concepts. We could write concept maps for specializations of QDictIterator, but that would result in an explosion of boilerplate.

Why is this a core issue?

Some people have suggested that this is not a problem with the core language at all, and people should just wait until their libraries are constrained. We don't see this as a practical approach, because we think the users should be able to use concepts as soon as they have a concept-capable implementation at their disposal, without having to wait for libraries to be constrained.

It is very likely that the necessary libraries will not be constrained at the moment concept implementations become available, and for some libraries, becoming constrained will take a long time, and further for some libraries, may never happen. Thus we think the problem is caused by the core language, and suggesting that libraries are constrained before they can be used with constrained templates is an impractical solution.

We don't think it's necessarily possible to constrain libraries from the top to bottom, so to speak. This is because the whole reason for doing external adaptation via concept maps (and concept map templates) is that the multiple template libraries need not know anything about each other, and thus it would be difficult to say which ones are at the "bottom" and which ones are on "top". Current popular template libraries can be mixed in multiple ways and directions, without them being aware of each other.

Solution options

We don't suggest solution options, because concepts are not part of C++0x, and thus the problem is not current. We do want concept designers to keep this issue in mind, so that existing code is easy to adapt for use with forthcoming concepts.