Commit dd8e0cbf authored by Robert Bradshaw's avatar Robert Bradshaw

Add a workaround for variables of default template parameter types.

parent 767fce81
......@@ -16,7 +16,7 @@ from .Code import UtilityCode, LazyUtilityCode, TempitaUtilityCode
from . import StringEncoding
from . import Naming
from .Errors import error
from .Errors import error, warning
class BaseType(object):
......@@ -3555,12 +3555,20 @@ class CppClassType(CType):
error(pos, "'%s' type is not a template" % self)
return error_type
if len(self.templates) - self.num_optional_templates <= len(template_values) < len(self.templates):
num_defaults = len(self.templates) - len(template_values)
partial_specialization = self.declaration_code('', template_params=template_values)
# Most of the time we don't need to declare anything typed to these
# default template arguments, but when we do there's no way in C++
# to reference this directly. However, it is common convention to
# provide a typedef in the template class that resolves to each
# template type. For now, allow the user to specify this name as
# the template parameter.
# TODO: Allow typedefs in cpp classes and search for it in this
# classes scope as a concrete name we could use.
template_values = template_values + [
TemplatePlaceholderType("%s %s::%s" % (
TemplatePlaceholderType.UNDECLARABLE_DEFAULT, partial_specialization, param.name),
True)
for param in self.templates[-self.num_optional_templates:]]
TemplatePlaceholderType(
"%s::%s" % (partial_specialization, param.name), True)
for param in self.templates[-num_defaults:]]
if len(self.templates) != len(template_values):
error(pos, "%s templated type receives %d arguments, got %d" %
(self.name, len(self.templates), len(template_values)))
......@@ -3684,17 +3692,12 @@ class CppClassType(CType):
class TemplatePlaceholderType(CType):
UNDECLARABLE_DEFAULT = "undeclarable default "
def __init__(self, name, optional=False):
self.name = name
self.optional = optional
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if self.name.startswith(self.UNDECLARABLE_DEFAULT) and not for_display:
error(None, "Can't declare variable of type '%s'"
% self.name[len(self.UNDECLARABLE_DEFAULT) + 1:])
if entity_code:
return self.name + " " + entity_code
else:
......
......@@ -68,7 +68,7 @@ document. Let's assume it will be in a header file called
void move(int dx, int dy);
};
}
and the implementation in the file called :file:`Rectangle.cpp`:
.. sourcecode:: c++
......@@ -104,7 +104,7 @@ and the implementation in the file called :file:`Rectangle.cpp`:
x1 += dx;
y1 += dy;
}
}
This is pretty dumb, but should suffice to demonstrate the steps involved.
......@@ -196,7 +196,7 @@ class name from Rectangle.h and adjust for Cython syntax, so now it becomes::
cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle:
Add public attributes
^^^^^^^^^^^^^^^^^^^^^^
......@@ -346,9 +346,9 @@ nested in Cython::
T& at(int)
iterator begin()
iterator end()
cdef vector[int].iterator iter #iter is declared as being of type vector<int>::iterator
Note that the nested class is declared with a ``cppclass`` but without a ``cdef``.
C++ operators not compatible with Python syntax
......@@ -409,8 +409,15 @@ Cython uses a bracket syntax for templating. A simple example for wrapping C++ v
del v
Multiple template parameters can be defined as a list, such as [T, U, V]
or [int, bool, char]. Template functions are defined similarly, with
Multiple template parameters can be defined as a list, such as ``[T, U, V]``
or ``[int, bool, char]``. Optional template parameters can be indicated
by writing ``[T, U, V=*]``. In the event that Cython needs to explicitly
reference a default template value for an incomplete template instantiation,
it will write ``MyClass<T, U>::V``, so if the class provides a typedef
for its template parameters it is preferable to use that name here.
Template functions are defined similarly to class templates, with
the template parameter list following the function name::
cdef extern from "<algorithm>" namespace "std":
......@@ -437,7 +444,7 @@ For example::
vect.push_back(i)
for i in range(10):
print vect[i]
The pxd files in ``/Cython/Includes/libcpp`` also work as good examples on
how to declare C++ classes.
......@@ -601,7 +608,7 @@ module which:
* includes the needed C headers in an extern "C" block
* contains minimal forwarding functions in C++, each of which calls the
respective pure-C function
respective pure-C function
Declaring/Using References
---------------------------
......@@ -614,5 +621,3 @@ C++ left-values
C++ allows functions returning a reference to be left-values. This is currently
not supported in Cython. ``cython.operator.dereference(foo)`` is also not
considered a left-value.
......@@ -3,14 +3,17 @@
from cython.operator import dereference as deref
cdef extern from "cpp_templates_helper.h":
cdef cppclass Wrap[T, S=*]:
cdef cppclass Wrap[T, AltType=*, UndeclarableAltType=*]:
Wrap(T)
void set(T)
T get()
bint operator==(Wrap[T])
S get_alt_type()
void set_alt_type(S)
AltType get_alt_type()
void set_alt_type(AltType)
UndeclarableAltType create()
bint accept(UndeclarableAltType)
cdef cppclass Pair[T1,T2]:
Pair(T1,T2)
......@@ -68,15 +71,17 @@ def test_default_template_arguments(double x):
"""
try:
a = new Wrap[double](x)
b = new Wrap[double, int](x)
b = new Wrap[double, int, long](x)
ax = a.get_alt_type()
a.set_alt_type(ax)
assert a.accept(a.create()) # never declared
# ax = a.get_alt_type()
# a.set_alt_type(ax)
a.set_alt_type(a.get_alt_type())
bx = b.get_alt_type()
b.set_alt_type(bx)
# bx = b.get_alt_type()
# b.set_alt_type(bx)
b.set_alt_type(b.get_alt_type())
bc = b.create() # declaration here is fine
assert b.accept(bc)
return a.get(), b.get()
finally:
......
template <typename T, typename S=T>
template <typename T, typename S=T, typename U=T>
class Wrap {
T value;
public:
typedef S AltType;
Wrap(T v) : value(v) { }
void set(T v) { value = v; }
T get(void) { return value; }
......@@ -9,6 +11,9 @@ public:
S get_alt_type(void) { return (S) value; }
void set_alt_type(S v) { value = (T) v; }
U create(void) { return (U) value; }
bool accept(U v) { return v == (U) value; }
};
template <class T1, class T2>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment