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 ...@@ -16,7 +16,7 @@ from .Code import UtilityCode, LazyUtilityCode, TempitaUtilityCode
from . import StringEncoding from . import StringEncoding
from . import Naming from . import Naming
from .Errors import error from .Errors import error, warning
class BaseType(object): class BaseType(object):
...@@ -3555,12 +3555,20 @@ class CppClassType(CType): ...@@ -3555,12 +3555,20 @@ class CppClassType(CType):
error(pos, "'%s' type is not a template" % self) error(pos, "'%s' type is not a template" % self)
return error_type return error_type
if len(self.templates) - self.num_optional_templates <= len(template_values) < len(self.templates): 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) 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 + [ template_values = template_values + [
TemplatePlaceholderType("%s %s::%s" % ( TemplatePlaceholderType(
TemplatePlaceholderType.UNDECLARABLE_DEFAULT, partial_specialization, param.name), "%s::%s" % (partial_specialization, param.name), True)
True) for param in self.templates[-num_defaults:]]
for param in self.templates[-self.num_optional_templates:]]
if len(self.templates) != len(template_values): if len(self.templates) != len(template_values):
error(pos, "%s templated type receives %d arguments, got %d" % error(pos, "%s templated type receives %d arguments, got %d" %
(self.name, len(self.templates), len(template_values))) (self.name, len(self.templates), len(template_values)))
...@@ -3684,17 +3692,12 @@ class CppClassType(CType): ...@@ -3684,17 +3692,12 @@ class CppClassType(CType):
class TemplatePlaceholderType(CType): class TemplatePlaceholderType(CType):
UNDECLARABLE_DEFAULT = "undeclarable default "
def __init__(self, name, optional=False): def __init__(self, name, optional=False):
self.name = name self.name = name
self.optional = optional self.optional = optional
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): 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: if entity_code:
return self.name + " " + entity_code return self.name + " " + entity_code
else: else:
......
...@@ -68,7 +68,7 @@ document. Let's assume it will be in a header file called ...@@ -68,7 +68,7 @@ document. Let's assume it will be in a header file called
void move(int dx, int dy); void move(int dx, int dy);
}; };
} }
and the implementation in the file called :file:`Rectangle.cpp`: and the implementation in the file called :file:`Rectangle.cpp`:
.. sourcecode:: c++ .. sourcecode:: c++
...@@ -104,7 +104,7 @@ and the implementation in the file called :file:`Rectangle.cpp`: ...@@ -104,7 +104,7 @@ and the implementation in the file called :file:`Rectangle.cpp`:
x1 += dx; x1 += dx;
y1 += dy; y1 += dy;
} }
} }
This is pretty dumb, but should suffice to demonstrate the steps involved. 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:: ...@@ -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 extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle: cdef cppclass Rectangle:
Add public attributes Add public attributes
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
...@@ -346,9 +346,9 @@ nested in Cython:: ...@@ -346,9 +346,9 @@ nested in Cython::
T& at(int) T& at(int)
iterator begin() iterator begin()
iterator end() iterator end()
cdef vector[int].iterator iter #iter is declared as being of type vector<int>::iterator 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``. Note that the nested class is declared with a ``cppclass`` but without a ``cdef``.
C++ operators not compatible with Python syntax 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 ...@@ -409,8 +409,15 @@ Cython uses a bracket syntax for templating. A simple example for wrapping C++ v
del v del v
Multiple template parameters can be defined as a list, such as [T, U, 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 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:: the template parameter list following the function name::
cdef extern from "<algorithm>" namespace "std": cdef extern from "<algorithm>" namespace "std":
...@@ -437,7 +444,7 @@ For example:: ...@@ -437,7 +444,7 @@ For example::
vect.push_back(i) vect.push_back(i)
for i in range(10): for i in range(10):
print vect[i] print vect[i]
The pxd files in ``/Cython/Includes/libcpp`` also work as good examples on The pxd files in ``/Cython/Includes/libcpp`` also work as good examples on
how to declare C++ classes. how to declare C++ classes.
...@@ -601,7 +608,7 @@ module which: ...@@ -601,7 +608,7 @@ module which:
* includes the needed C headers in an extern "C" block * includes the needed C headers in an extern "C" block
* contains minimal forwarding functions in C++, each of which calls the * contains minimal forwarding functions in C++, each of which calls the
respective pure-C function respective pure-C function
Declaring/Using References Declaring/Using References
--------------------------- ---------------------------
...@@ -614,5 +621,3 @@ C++ left-values ...@@ -614,5 +621,3 @@ C++ left-values
C++ allows functions returning a reference to be left-values. This is currently C++ allows functions returning a reference to be left-values. This is currently
not supported in Cython. ``cython.operator.dereference(foo)`` is also not not supported in Cython. ``cython.operator.dereference(foo)`` is also not
considered a left-value. considered a left-value.
...@@ -3,14 +3,17 @@ ...@@ -3,14 +3,17 @@
from cython.operator import dereference as deref from cython.operator import dereference as deref
cdef extern from "cpp_templates_helper.h": cdef extern from "cpp_templates_helper.h":
cdef cppclass Wrap[T, S=*]: cdef cppclass Wrap[T, AltType=*, UndeclarableAltType=*]:
Wrap(T) Wrap(T)
void set(T) void set(T)
T get() T get()
bint operator==(Wrap[T]) bint operator==(Wrap[T])
S get_alt_type() AltType get_alt_type()
void set_alt_type(S) void set_alt_type(AltType)
UndeclarableAltType create()
bint accept(UndeclarableAltType)
cdef cppclass Pair[T1,T2]: cdef cppclass Pair[T1,T2]:
Pair(T1,T2) Pair(T1,T2)
...@@ -68,15 +71,17 @@ def test_default_template_arguments(double x): ...@@ -68,15 +71,17 @@ def test_default_template_arguments(double x):
""" """
try: try:
a = new Wrap[double](x) 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() bx = b.get_alt_type()
# a.set_alt_type(ax) b.set_alt_type(bx)
a.set_alt_type(a.get_alt_type())
# bx = b.get_alt_type() bc = b.create() # declaration here is fine
# b.set_alt_type(bx) assert b.accept(bc)
b.set_alt_type(b.get_alt_type())
return a.get(), b.get() return a.get(), b.get()
finally: finally:
......
template <typename T, typename S=T> template <typename T, typename S=T, typename U=T>
class Wrap { class Wrap {
T value; T value;
public: public:
typedef S AltType;
Wrap(T v) : value(v) { } Wrap(T v) : value(v) { }
void set(T v) { value = v; } void set(T v) { value = v; }
T get(void) { return value; } T get(void) { return value; }
...@@ -9,6 +11,9 @@ public: ...@@ -9,6 +11,9 @@ public:
S get_alt_type(void) { return (S) value; } S get_alt_type(void) { return (S) value; }
void set_alt_type(S v) { value = (T) v; } 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> 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