Author: Wim Lavrijsen <wlavrij...@lbl.gov>
Branch: 
Changeset: r92872:0b8528722439
Date: 2017-10-28 15:55 -0700
http://bitbucket.org/pypy/pypy/changeset/0b8528722439/

Log:    merge cppyy-packaging with improved consistency for cppyy CPython
        <-> PyPy

diff too long, truncating to 2000 out of 3147 lines

diff --git a/pypy/module/_cppyy/__init__.py b/pypy/module/_cppyy/__init__.py
--- a/pypy/module/_cppyy/__init__.py
+++ b/pypy/module/_cppyy/__init__.py
@@ -7,7 +7,7 @@
     interpleveldefs = {
         '_resolve_name'          : 'interp_cppyy.resolve_name',
         '_scope_byname'          : 'interp_cppyy.scope_byname',
-        '_template_byname'       : 'interp_cppyy.template_byname',
+        '_is_template'           : 'interp_cppyy.is_template',
         '_std_string_name'       : 'interp_cppyy.std_string_name',
         '_set_class_generator'   : 'interp_cppyy.set_class_generator',
         '_set_function_generator': 'interp_cppyy.set_function_generator',
@@ -15,7 +15,9 @@
         '_get_nullptr'           : 'interp_cppyy.get_nullptr',
         'CPPClassBase'           : 'interp_cppyy.W_CPPClass',
         'addressof'              : 'interp_cppyy.addressof',
+        '_bind_object'           : 'interp_cppyy._bind_object',
         'bind_object'            : 'interp_cppyy.bind_object',
+        'move'                   : 'interp_cppyy.move',
     }
 
     appleveldefs = {
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py 
b/pypy/module/_cppyy/capi/loadable_capi.py
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -217,7 +217,8 @@
             'method_req_args'          : ([c_scope, c_index],         c_int),
             'method_arg_type'          : ([c_scope, c_index, c_int],  
c_ccharp),
             'method_arg_default'       : ([c_scope, c_index, c_int],  
c_ccharp),
-            'method_signature'         : ([c_scope, c_index],         
c_ccharp),
+            'method_signature'         : ([c_scope, c_index, c_int],  
c_ccharp),
+            'method_prototype'         : ([c_scope, c_index, c_int],  
c_ccharp),
 
             'method_is_template'       : ([c_scope, c_index],         c_int),
             'method_num_template_args' : ([c_scope, c_index],         c_int),
@@ -498,9 +499,12 @@
 def c_method_arg_default(space, cppscope, index, arg_index):
     args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
     return charp2str_free(space, call_capi(space, 'method_arg_default', args))
-def c_method_signature(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
+def c_method_signature(space, cppscope, index, show_formalargs=True):
+    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
     return charp2str_free(space, call_capi(space, 'method_signature', args))
+def c_method_prototype(space, cppscope, index, show_formalargs=True):
+    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+    return charp2str_free(space, call_capi(space, 'method_prototype', args))
 
 def c_method_is_template(space, cppscope, index):
     args = [_ArgH(cppscope.handle), _ArgL(index)]
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -4,7 +4,7 @@
 
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.rarithmetic import r_singlefloat, r_longfloat
-from rpython.rlib import rfloat
+from rpython.rlib import rfloat, rawrefcount
 
 from pypy.module._rawffi.interp_rawffi import letter2tp
 from pypy.module._rawffi.array import W_Array, W_ArrayInstance
@@ -21,9 +21,9 @@
 # match for the qualified type.
 
 
-def get_rawobject(space, w_obj):
+def get_rawobject(space, w_obj, can_be_None=True):
     from pypy.module._cppyy.interp_cppyy import W_CPPClass
-    cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
+    cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=can_be_None)
     if cppinstance:
         rawobject = cppinstance.get_rawobject()
         assert lltype.typeOf(rawobject) == capi.C_OBJECT
@@ -48,17 +48,16 @@
     return capi.C_NULL_OBJECT
 
 def is_nullpointer_specialcase(space, w_obj):
-    # 0, None, and nullptr may serve as "NULL", check for any of them
+    # 0 and nullptr may serve as "NULL"
 
     # integer 0
     try:
         return space.int_w(w_obj) == 0
     except Exception:
         pass
-    # None or nullptr
+    # C++-style nullptr
     from pypy.module._cppyy import interp_cppyy
-    return space.is_true(space.is_(w_obj, space.w_None)) or \
-        space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
+    return space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
 
 def get_rawbuffer(space, w_obj):
     # raw buffer
@@ -74,7 +73,7 @@
             return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
     except Exception:
         pass
-    # pre-defined NULL
+    # pre-defined nullptr
     if is_nullpointer_specialcase(space, w_obj):
         return rffi.cast(rffi.VOIDP, 0)
     raise TypeError("not an addressable buffer")
@@ -392,6 +391,7 @@
     _immutable_fields_ = ['typecode']
     typecode = 'g'
 
+
 class CStringConverter(TypeConverter):
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.LONGP, address)
@@ -408,18 +408,27 @@
     def free_argument(self, space, arg, call_local):
         lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
 
+class CStringConverterWithSize(CStringConverter):
+    _immutable_fields_ = ['size']
+
+    def __init__(self, space, extra):
+        self.size = extra
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = self._get_raw_address(space, w_obj, offset)
+        charpptr = rffi.cast(rffi.CCHARP, address)
+        strsize = self.size
+        if charpptr[self.size-1] == '\0':
+            strsize = self.size-1  # rffi will add \0 back
+        return space.newbytes(rffi.charpsize2str(charpptr, strsize))
+
 
 class VoidPtrConverter(TypeConverter):
     def _unwrap_object(self, space, w_obj):
         try:
             obj = get_rawbuffer(space, w_obj)
         except TypeError:
-            try:
-                # TODO: accept a 'capsule' rather than naked int
-                # (do accept int(0), though)
-                obj = rffi.cast(rffi.VOIDP, space.uint_w(w_obj))
-            except Exception:
-                obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+            obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj, False))
         return obj
 
     def cffi_type(self, space):
@@ -463,12 +472,12 @@
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
         ba = rffi.cast(rffi.CCHARP, address)
-        r = rffi.cast(rffi.VOIDPP, call_local)
         try:
-            r[0] = get_rawbuffer(space, w_obj)
+            x[0] = get_rawbuffer(space, w_obj)
         except TypeError:
+            r = rffi.cast(rffi.VOIDPP, call_local)
             r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
-        x[0] = rffi.cast(rffi.VOIDP, call_local)
+            x[0] = rffi.cast(rffi.VOIDP, call_local)
         ba[capi.c_function_arg_typeoffset(space)] = self.typecode
 
     def finalize_call(self, space, w_obj, call_local):
@@ -495,9 +504,13 @@
     def _unwrap_object(self, space, w_obj):
         from pypy.module._cppyy.interp_cppyy import W_CPPClass
         if isinstance(w_obj, W_CPPClass):
-            if capi.c_is_subtype(space, w_obj.cppclass, self.clsdecl):
+            from pypy.module._cppyy.interp_cppyy import 
INSTANCE_FLAGS_IS_R_VALUE
+            if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
+                # reject moves as all are explicit
+                raise ValueError("lvalue expected")
+            if capi.c_is_subtype(space, w_obj.clsdecl, self.clsdecl):
                 rawobject = w_obj.get_rawobject()
-                offset = capi.c_base_offset(space, w_obj.cppclass, 
self.clsdecl, rawobject, 1)
+                offset = capi.c_base_offset(space, w_obj.clsdecl, 
self.clsdecl, rawobject, 1)
                 obj_address = capi.direct_ptradd(rawobject, offset)
                 return rffi.cast(capi.C_OBJECT, obj_address)
         raise oefmt(space.w_TypeError,
@@ -518,6 +531,17 @@
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
 
+class InstanceMoveConverter(InstanceRefConverter):
+    def _unwrap_object(self, space, w_obj):
+        # moving is same as by-ref, but have to check that move is allowed
+        from pypy.module._cppyy.interp_cppyy import W_CPPClass, 
INSTANCE_FLAGS_IS_R_VALUE
+        if isinstance(w_obj, W_CPPClass):
+            if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
+                w_obj.flags &= ~INSTANCE_FLAGS_IS_R_VALUE
+                return InstanceRefConverter._unwrap_object(self, space, w_obj)
+        raise oefmt(space.w_ValueError, "object is not an rvalue")
+
+
 class InstanceConverter(InstanceRefConverter):
 
     def convert_argument_libffi(self, space, w_obj, address, call_local):
@@ -527,7 +551,7 @@
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, 
offset))
         from pypy.module._cppyy import interp_cppyy
-        return interp_cppyy.wrap_cppobject(space, address, self.clsdecl, 
do_cast=False)
+        return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, 
do_cast=False)
 
     def to_memory(self, space, w_obj, w_value, offset):
         self._is_abstract(space)
@@ -548,7 +572,7 @@
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, 
offset))
         from pypy.module._cppyy import interp_cppyy
-        return interp_cppyy.wrap_cppobject(space, address, self.clsdecl, 
do_cast=False)
+        return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, 
do_cast=False)
 
     def to_memory(self, space, w_obj, w_value, offset):
         address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, 
offset))
@@ -582,8 +606,8 @@
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, 
offset))
         from pypy.module._cppyy import interp_cppyy
-        return interp_cppyy.wrap_cppobject(space, address, self.clsdecl,
-                                           do_cast=False, is_ref=True)
+        return interp_cppyy.wrap_cppinstance(
+            space, address, self.clsdecl, do_cast=False, is_ref=True)
 
 class StdStringConverter(InstanceConverter):
 
@@ -606,7 +630,7 @@
             assign = self.clsdecl.get_overload("__assign__")
             from pypy.module._cppyy import interp_cppyy
             assign.call(
-                interp_cppyy.wrap_cppobject(space, address, self.clsdecl, 
do_cast=False), [w_value])
+                interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, 
do_cast=False), [w_value])
         except Exception:
             InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
 
@@ -672,7 +696,7 @@
 
 _converters = {}         # builtin and custom types
 _a_converters = {}       # array and ptr versions of above
-def get_converter(space, name, default):
+def get_converter(space, _name, default):
     # The matching of the name to a converter should follow:
     #   1) full, exact match
     #       1a) const-removed match
@@ -680,9 +704,9 @@
     #   3) accept ref as pointer (for the stubs, const& can be
     #       by value, but that does not work for the ffi path)
     #   4) generalized cases (covers basically all user classes)
-    #   5) void converter, which fails on use
+    #   5) void* or void converter (which fails on use)
 
-    name = capi.c_resolve_name(space, name)
+    name = capi.c_resolve_name(space, _name)
 
     #   1) full, exact match
     try:
@@ -701,7 +725,7 @@
     clean_name = capi.c_resolve_name(space, helper.clean_type(name))
     try:
         # array_index may be negative to indicate no size or no size found
-        array_size = helper.array_size(name)
+        array_size = helper.array_size(_name)     # uses original arg
         return _a_converters[clean_name+compound](space, array_size)
     except KeyError:
         pass
@@ -719,6 +743,8 @@
             return InstancePtrConverter(space, clsdecl)
         elif compound == "&":
             return InstanceRefConverter(space, clsdecl)
+        elif compound == "&&":
+            return InstanceMoveConverter(space, clsdecl)
         elif compound == "**":
             return InstancePtrPtrConverter(space, clsdecl)
         elif compound == "":
@@ -726,11 +752,13 @@
     elif capi.c_is_enum(space, clean_name):
         return _converters['unsigned'](space, default)
 
-    #   5) void converter, which fails on use
-    #
+    #   5) void* or void converter (which fails on use)
+    if 0 <= compound.find('*'):
+        return VoidPtrConverter(space, default)  # "user knows best"
+
     # return a void converter here, so that the class can be build even
-    # when some types are unknown; this overload will simply fail on use
-    return VoidConverter(space, name)
+    # when some types are unknown
+    return VoidConverter(space, name)            # fails on use
 
 
 _converters["bool"]                     = BoolConverter
@@ -847,6 +875,10 @@
         for name in names:
             _a_converters[name+'[]'] = ArrayConverter
             _a_converters[name+'*']  = PtrConverter
+
+    # special case, const char* w/ size and w/o '\0'
+    _a_converters["const char[]"] = CStringConverterWithSize
+
 _build_array_converters()
 
 # add another set of aliased names
diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py
--- a/pypy/module/_cppyy/executor.py
+++ b/pypy/module/_cppyy/executor.py
@@ -159,7 +159,7 @@
         from pypy.module._cppyy import interp_cppyy
         long_result = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
         ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        pyres = interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+        pyres = interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
         return pyres
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
@@ -167,7 +167,7 @@
         result = rffi.ptradd(buffer, cif_descr.exchange_result)
         from pypy.module._cppyy import interp_cppyy
         ptr_result = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, 
result)[0])
-        return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
 
 class InstancePtrPtrExecutor(InstancePtrExecutor):
 
@@ -176,7 +176,7 @@
         voidp_result = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
         ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
         ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
-        return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
@@ -188,8 +188,8 @@
         from pypy.module._cppyy import interp_cppyy
         long_result = capi.c_call_o(space, cppmethod, cppthis, num_args, args, 
self.cppclass)
         ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass,
-                                           do_cast=False, python_owns=True, 
fresh=True)
+        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass,
+                                             do_cast=False, python_owns=True, 
fresh=True)
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
diff --git a/pypy/module/_cppyy/include/capi.h 
b/pypy/module/_cppyy/include/capi.h
--- a/pypy/module/_cppyy/include/capi.h
+++ b/pypy/module/_cppyy/include/capi.h
@@ -19,14 +19,15 @@
     RPY_EXTERN
     int cppyy_num_scopes(cppyy_scope_t parent);
     RPY_EXTERN
-    char* cppyy_scope_name(cppyy_scope_t parent, int iscope);
-
+    char* cppyy_scope_name(cppyy_scope_t parent, cppyy_index_t iscope);
     RPY_EXTERN
     char* cppyy_resolve_name(const char* cppitem_name);
     RPY_EXTERN
     cppyy_scope_t cppyy_get_scope(const char* scope_name);
     RPY_EXTERN
     cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj);
+    RPY_EXTERN
+    size_t cppyy_size_of(cppyy_type_t klass);
 
     /* memory management 
------------------------------------------------------ */
     RPY_EXTERN
@@ -120,6 +121,8 @@
     RPY_EXTERN
     char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx);
     RPY_EXTERN
+    char* cppyy_method_mangled_name(cppyy_scope_t scope, cppyy_index_t idx);
+    RPY_EXTERN
     char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx);
     RPY_EXTERN
     int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx);
@@ -130,7 +133,9 @@
     RPY_EXTERN
     char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int 
arg_index);
     RPY_EXTERN
-    char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx);
+    char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx, int 
show_formalargs);
+    RPY_EXTERN
+    char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_index_t idx, int 
show_formalargs);
 
     RPY_EXTERN
     int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx);
@@ -147,8 +152,12 @@
 
     /* method properties 
------------------------------------------------------ */
     RPY_EXTERN
+    int cppyy_is_publicmethod(cppyy_type_t type, cppyy_index_t idx);
+    RPY_EXTERN
     int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx);
     RPY_EXTERN
+    int cppyy_is_destructor(cppyy_type_t type, cppyy_index_t idx);
+    RPY_EXTERN
     int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx);
 
     /* data member reflection information 
------------------------------------- */
diff --git a/pypy/module/_cppyy/interp_cppyy.py 
b/pypy/module/_cppyy/interp_cppyy.py
--- a/pypy/module/_cppyy/interp_cppyy.py
+++ b/pypy/module/_cppyy/interp_cppyy.py
@@ -2,7 +2,7 @@
 
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef, GetSetProperty, 
interp_attrproperty, interp_attrproperty_w
+from pypy.interpreter.typedef import TypeDef, GetSetProperty, 
interp_attrproperty
 from pypy.interpreter.baseobjspace import W_Root
 
 from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
@@ -15,6 +15,10 @@
 from pypy.module._cppyy import converter, executor, ffitypes, helper
 
 
+INSTANCE_FLAGS_PYTHON_OWNS = 0x0001
+INSTANCE_FLAGS_IS_REF      = 0x0002
+INSTANCE_FLAGS_IS_R_VALUE  = 0x0004
+
 class FastCallNotPossible(Exception):
     pass
 
@@ -33,16 +37,21 @@
 
 class State(object):
     def __init__(self, space):
+        # final scoped name -> opaque handle
         self.cppscope_cache = {
-            "void" : W_CPPClassDecl(space, "void", capi.C_NULL_TYPE) }
+            'void' : W_CPPClassDecl(space, capi.C_NULL_TYPE, 'void') }
+        # opaque handle -> app-level python class
+        self.cppclass_registry = {}
+        # app-level class generator callback
+        self.w_clgen_callback = None
+        # app-level function generator callback (currently not used)
+        self.w_fngen_callback = None
+        # C++11's nullptr
         self.w_nullptr = None
-        self.cpptemplate_cache = {}
-        self.cppclass_registry = {}
-        self.w_clgen_callback = None
-        self.w_fngen_callback = None
 
 def get_nullptr(space):
-    if hasattr(space, "fake"):
+    # construct a unique address that compares to NULL, serves as nullptr
+    if hasattr(space, 'fake'):
         raise NotImplementedError
     state = space.fromcache(State)
     if state.w_nullptr is None:
@@ -58,52 +67,48 @@
         state.w_nullptr = nullarr
     return state.w_nullptr
 
-@unwrap_spec(name='text')
-def resolve_name(space, name):
-    return space.newtext(capi.c_resolve_name(space, name))
+@unwrap_spec(scoped_name='text')
+def resolve_name(space, scoped_name):
+    return space.newtext(capi.c_resolve_name(space, scoped_name))
 
-@unwrap_spec(name='text')
-def scope_byname(space, name):
-    true_name = capi.c_resolve_name(space, name)
 
+# memoized lookup of handles by final, scoped, name of classes/namespaces
+@unwrap_spec(final_scoped_name='text')
+def scope_byname(space, final_scoped_name):
     state = space.fromcache(State)
     try:
-        return state.cppscope_cache[true_name]
+        return state.cppscope_cache[final_scoped_name]
     except KeyError:
         pass
 
-    opaque_handle = capi.c_get_scope_opaque(space, true_name)
+    opaque_handle = capi.c_get_scope_opaque(space, final_scoped_name)
     assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
     if opaque_handle:
-        final_name = capi.c_final_name(space, opaque_handle)
-        if capi.c_is_namespace(space, opaque_handle):
-            cppscope = W_CPPNamespaceDecl(space, final_name, opaque_handle)
-        elif capi.c_has_complex_hierarchy(space, opaque_handle):
-            cppscope = W_CPPComplexClassDecl(space, final_name, opaque_handle)
+        isns = capi.c_is_namespace(space, opaque_handle)
+        if isns:
+            cppscope = W_CPPNamespaceDecl(space, opaque_handle, 
final_scoped_name)
         else:
-            cppscope = W_CPPClassDecl(space, final_name, opaque_handle)
-        state.cppscope_cache[name] = cppscope
+            if capi.c_has_complex_hierarchy(space, opaque_handle):
+                cppscope = W_CPPComplexClassDecl(space, opaque_handle, 
final_scoped_name)
+            else:
+                cppscope = W_CPPClassDecl(space, opaque_handle, 
final_scoped_name)
 
-        cppscope._build_methods()
-        cppscope._find_datamembers()
+        # store in the cache to prevent recursion
+        state.cppscope_cache[final_scoped_name] = cppscope
+
+        if not isns:
+            # build methods/data; TODO: also defer this for classes (a 
functional __dir__
+            # and instrospection for help() is enough and allows more lazy 
loading)
+            cppscope._build_methods()
+            cppscope._find_datamembers()
+
         return cppscope
 
     return None
 
-@unwrap_spec(name='text')
-def template_byname(space, name):
-    state = space.fromcache(State)
-    try:
-        return state.cpptemplate_cache[name]
-    except KeyError:
-        pass
-
-    if capi.c_is_template(space, name):
-        cpptemplate = W_CPPTemplateType(space, name)
-        state.cpptemplate_cache[name] = cpptemplate
-        return cpptemplate
-
-    return None
+@unwrap_spec(final_scoped_name='text')
+def is_template(space, final_scoped_name):
+    return space.newbool(capi.c_is_template(space, final_scoped_name))
 
 def std_string_name(space):
     return space.newtext(capi.std_string_name)
@@ -189,8 +194,13 @@
         # check number of given arguments against required (== total - 
defaults)
         args_expected = len(self.arg_defs)
         args_given = len(args_w)
-        if args_expected < args_given or args_given < self.args_required:
-            raise oefmt(self.space.w_TypeError, "wrong number of arguments")
+
+        if args_given < self.args_required:
+            raise oefmt(self.space.w_TypeError,
+                "takes at least %d arguments (%d given)", self.args_required, 
args_given)
+        elif args_expected < args_given:
+            raise oefmt(self.space.w_TypeError,
+                "takes at most %d arguments (%d given)", args_expected, 
args_given)
 
         # initial setup of converters, executors, and libffi (if available)
         if self.converters is None:
@@ -376,8 +386,11 @@
             conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i), 
loc_i)
         capi.c_deallocate_function_args(self.space, args)
 
-    def signature(self):
-        return capi.c_method_signature(self.space, self.scope, self.index)
+    def signature(self, show_formalargs=True):
+        return capi.c_method_signature(self.space, self.scope, self.index, 
show_formalargs)
+
+    def prototype(self, show_formalargs=True):
+        return capi.c_method_prototype(self.space, self.scope, self.index, 
show_formalargs)
 
     def priority(self):
         total_arg_priority = 0
@@ -391,7 +404,7 @@
             lltype.free(self.cif_descr, flavor='raw')
 
     def __repr__(self):
-        return "CPPMethod: %s" % self.signature()
+        return "CPPMethod: %s" % self.prototype()
 
     def _freeze_(self):
         assert 0, "you should never have a pre-built instance of this!"
@@ -407,7 +420,7 @@
         return capi.C_NULL_OBJECT
 
     def __repr__(self):
-        return "CPPFunction: %s" % self.signature()
+        return "CPPFunction: %s" % self.prototype()
 
 
 class CPPTemplatedCall(CPPMethod):
@@ -440,7 +453,7 @@
         return CPPMethod.call(self, cppthis, args_w)
 
     def __repr__(self):
-        return "CPPTemplatedCall: %s" % self.signature()
+        return "CPPTemplatedCall: %s" % self.prototype()
 
 
 class CPPConstructor(CPPMethod):
@@ -462,7 +475,7 @@
         return CPPMethod.call(self, cppthis, args_w)
 
     def __repr__(self):
-        return "CPPConstructor: %s" % self.signature()
+        return "CPPConstructor: %s" % self.prototype()
 
 
 class CPPSetItem(CPPMethod):
@@ -549,12 +562,12 @@
                     w_exc_type = e.w_type
                 elif all_same_type and not e.match(self.space, w_exc_type):
                     all_same_type = False
-                errmsg += '\n  '+cppyyfunc.signature()+' =>\n'
+                errmsg += '\n  '+cppyyfunc.prototype()+' =>\n'
                 errmsg += '    '+e.errorstr(self.space)
             except Exception as e:
                 # can not special case this for non-overloaded functions as we 
anyway need an
                 # OperationError error down from here
-                errmsg += '\n  '+cppyyfunc.signature()+' =>\n'
+                errmsg += '\n  '+cppyyfunc.prototype()+' =>\n'
                 errmsg += '    Exception: '+str(e)
 
         if all_same_type and w_exc_type is not None:
@@ -562,20 +575,20 @@
         else:
             raise OperationError(self.space.w_TypeError, 
self.space.newtext(errmsg))
 
-    def signature(self):
-        sig = self.functions[0].signature()
+    def prototype(self):
+        sig = self.functions[0].prototype()
         for i in range(1, len(self.functions)):
-            sig += '\n'+self.functions[i].signature()
+            sig += '\n'+self.functions[i].prototype()
         return self.space.newtext(sig)
 
     def __repr__(self):
-        return "W_CPPOverload(%s)" % [f.signature() for f in self.functions]
+        return "W_CPPOverload(%s)" % [f.prototype() for f in self.functions]
 
 W_CPPOverload.typedef = TypeDef(
     'CPPOverload',
     is_static = interp2app(W_CPPOverload.is_static),
     call = interp2app(W_CPPOverload.call),
-    signature = interp2app(W_CPPOverload.signature),
+    prototype = interp2app(W_CPPOverload.prototype),
 )
 
 
@@ -591,24 +604,40 @@
     @jit.unroll_safe
     @unwrap_spec(args_w='args_w')
     def call(self, w_cppinstance, args_w):
+        # TODO: factor out the following:
+        if capi.c_is_abstract(self.space, self.scope.handle):
+            raise oefmt(self.space.w_TypeError,
+                        "cannot instantiate abstract class '%s'",
+                        self.scope.name)
         w_result = W_CPPOverload.call(self, w_cppinstance, args_w)
         newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result))
         cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, 
can_be_None=True)
         if cppinstance is not None:
             cppinstance._rawobject = newthis
             memory_regulator.register(cppinstance)
-            return w_cppinstance
-        return wrap_cppobject(self.space, newthis, self.functions[0].scope,
-                              do_cast=False, python_owns=True, fresh=True)
 
     def __repr__(self):
-        return "W_CPPConstructorOverload(%s)" % [f.signature() for f in 
self.functions]
+        return "W_CPPConstructorOverload(%s)" % [f.prototype() for f in 
self.functions]
 
 W_CPPConstructorOverload.typedef = TypeDef(
     'CPPConstructorOverload',
     is_static = interp2app(W_CPPConstructorOverload.is_static),
     call = interp2app(W_CPPConstructorOverload.call),
-    signature = interp2app(W_CPPOverload.signature),
+    prototype = interp2app(W_CPPConstructorOverload.prototype),
+)
+
+
+class W_CPPTemplateOverload(W_CPPOverload):
+    @unwrap_spec(args_w='args_w')
+    def __getitem__(self, args_w):
+        pass
+
+    def __repr__(self):
+        return "W_CPPTemplateOverload(%s)" % [f.prototype() for f in 
self.functions]
+
+W_CPPTemplateOverload.typedef = TypeDef(
+    'CPPTemplateOverload',
+    __getitem__ = interp2app(W_CPPTemplateOverload.call),
 )
 
 
@@ -622,6 +651,9 @@
     def __call__(self, args_w):
         return self.method.bound_call(self.cppthis, args_w)
 
+    def __repr__(self):
+        return "W_CPPBoundMethod(%s)" % [f.prototype() for f in self.functions]
+
 W_CPPBoundMethod.typedef = TypeDef(
     'CPPBoundMethod',
     __call__ = interp2app(W_CPPBoundMethod.__call__),
@@ -643,8 +675,8 @@
 
     def _get_offset(self, cppinstance):
         if cppinstance:
-            assert lltype.typeOf(cppinstance.cppclass.handle) == 
lltype.typeOf(self.scope.handle)
-            offset = self.offset + 
cppinstance.cppclass.get_base_offset(cppinstance, self.scope)
+            assert lltype.typeOf(cppinstance.clsdecl.handle) == 
lltype.typeOf(self.scope.handle)
+            offset = self.offset + 
cppinstance.clsdecl.get_base_offset(cppinstance, self.scope)
         else:
             offset = self.offset
         return offset
@@ -652,7 +684,7 @@
     def get(self, w_cppinstance, w_pycppclass):
         cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, 
can_be_None=True)
         if not cppinstance:
-            raise oefmt(self.space.w_ReferenceError,
+            raise oefmt(self.space.w_AttributeError,
                         "attribute access requires an instance")
         offset = self._get_offset(cppinstance)
         return self.converter.from_memory(self.space, w_cppinstance, 
w_pycppclass, offset)
@@ -660,7 +692,7 @@
     def set(self, w_cppinstance, w_value):
         cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, 
can_be_None=True)
         if not cppinstance:
-            raise oefmt(self.space.w_ReferenceError,
+            raise oefmt(self.space.w_AttributeError,
                         "attribute access requires an instance")
         offset = self._get_offset(cppinstance)
         self.converter.to_memory(self.space, w_cppinstance, w_value, offset)
@@ -705,12 +737,12 @@
         return space.w_False
 
 class W_CPPScopeDecl(W_Root):
-    _attrs_ = ['space', 'name', 'handle', 'methods', 'datamembers']
+    _attrs_ = ['space', 'handle', 'name', 'methods', 'datamembers']
     _immutable_fields_ = ['handle', 'name']
 
-    def __init__(self, space, name, opaque_handle):
+    def __init__(self, space, opaque_handle, final_scoped_name):
         self.space = space
-        self.name = name
+        self.name = final_scoped_name
         assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
         self.handle = opaque_handle
         self.methods = {}
@@ -753,7 +785,7 @@
         overload = self.get_overload(name)
         sig = '(%s)' % signature
         for f in overload.functions:
-            if 0 < f.signature().find(sig):
+            if f.signature(False) == sig:
                 return W_CPPOverload(self.space, self, [f])
         raise oefmt(self.space.w_LookupError, "no overload matches signature")
 
@@ -769,6 +801,9 @@
 # classes for inheritance. Both are python classes, though, and refactoring
 # may be in order at some point.
 class W_CPPNamespaceDecl(W_CPPScopeDecl):
+    _attrs_ = ['space', 'handle', 'name', 'methods', 'datamembers']
+    _immutable_fields_ = ['handle', 'name']
+
     def _make_cppfunction(self, pyname, index):
         num_args = capi.c_method_num_args(self.space, self, index)
         args_required = capi.c_method_req_args(self.space, self, index)
@@ -779,9 +814,6 @@
             arg_defs.append((arg_type, arg_dflt))
         return CPPFunction(self.space, self, index, arg_defs, args_required)
 
-    def _build_methods(self):
-        pass       # force lazy lookups in namespaces
-
     def _make_datamember(self, dm_name, dm_idx):
         type_name = capi.c_datamember_type(self.space, self, dm_idx)
         offset = capi.c_datamember_offset(self.space, self, dm_idx)
@@ -791,9 +823,6 @@
         self.datamembers[dm_name] = datamember
         return datamember
 
-    def _find_datamembers(self):
-        pass       # force lazy lookups in namespaces
-
     def find_overload(self, meth_name):
         indices = capi.c_method_indices_from_name(self.space, self, meth_name)
         if not indices:
@@ -855,18 +884,21 @@
 
 
 class W_CPPClassDecl(W_CPPScopeDecl):
-    _attrs_ = ['space', 'name', 'handle', 'methods', 'datamembers']
-    _immutable_fields_ = ['handle', 'constructor', 'methods[*]', 
'datamembers[*]']
+    _attrs_ = ['space', 'handle', 'name', 'methods', 'datamembers']
+    _immutable_fields_ = ['handle', 'name', 'methods[*]', 'datamembers[*]']
 
     def _build_methods(self):
         assert len(self.methods) == 0
         methods_temp = {}
         for i in range(capi.c_num_methods(self.space, self)):
             idx = capi.c_method_index_at(self.space, self, i)
-            pyname = helper.map_operator_name(self.space,
-                capi.c_method_name(self.space, self, idx),
-                capi.c_method_num_args(self.space, self, idx),
-                capi.c_method_result_type(self.space, self, idx))
+            if capi.c_is_constructor(self.space, self, idx):
+                pyname = '__init__'
+            else:
+                pyname = helper.map_operator_name(self.space,
+                    capi.c_method_name(self.space, self, idx),
+                    capi.c_method_num_args(self.space, self, idx),
+                    capi.c_method_result_type(self.space, self, idx))
             cppmethod = self._make_cppfunction(pyname, idx)
             methods_temp.setdefault(pyname, []).append(cppmethod)
         # the following covers the case where the only kind of operator[](idx)
@@ -883,7 +915,7 @@
         # create the overload methods from the method sets
         for pyname, methods in methods_temp.iteritems():
             CPPMethodSort(methods).sort()
-            if pyname == self.name:
+            if pyname == '__init__':
                 overload = W_CPPConstructorOverload(self.space, self, 
methods[:])
             else:
                 overload = W_CPPOverload(self.space, self, methods[:])
@@ -934,11 +966,11 @@
         raise self.missing_attribute_error(name)
 
     def get_base_offset(self, cppinstance, calling_scope):
-        assert self == cppinstance.cppclass
+        assert self == cppinstance.clsdecl
         return 0
 
     def get_cppthis(self, cppinstance, calling_scope):
-        assert self == cppinstance.cppclass
+        assert self == cppinstance.clsdecl
         return cppinstance.get_rawobject()
 
     def is_namespace(self):
@@ -973,13 +1005,13 @@
 
 class W_CPPComplexClassDecl(W_CPPClassDecl):
     def get_base_offset(self, cppinstance, calling_scope):
-        assert self == cppinstance.cppclass
+        assert self == cppinstance.clsdecl
         offset = capi.c_base_offset(self.space,
                                     self, calling_scope, 
cppinstance.get_rawobject(), 1)
         return offset
 
     def get_cppthis(self, cppinstance, calling_scope):
-        assert self == cppinstance.cppclass
+        assert self == cppinstance.clsdecl
         offset = self.get_base_offset(cppinstance, calling_scope)
         return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
 
@@ -997,70 +1029,56 @@
 W_CPPComplexClassDecl.typedef.acceptable_as_base_class = False
 
 
-class W_CPPTemplateType(W_Root):
-    _attrs_ = ['space', 'name']
-    _immutable_fields = ['name']
-
-    def __init__(self, space, name):
-        self.space = space
-        self.name = name
-
-    @unwrap_spec(args_w='args_w')
-    def __call__(self, args_w):
-        # TODO: this is broken but unused (see pythonify.py)
-        fullname = "".join([self.name, '<', self.space.text_w(args_w[0]), '>'])
-        return scope_byname(self.space, fullname)
-
-W_CPPTemplateType.typedef = TypeDef(
-    'CPPTemplateType',
-    __call__ = interp2app(W_CPPTemplateType.__call__),
-)
-W_CPPTemplateType.typedef.acceptable_as_base_class = False
-
-
 class W_CPPClass(W_Root):
-    _attrs_ = ['space', 'cppclass', '_rawobject', 'isref', 'python_owns',
+    _attrs_ = ['space', 'clsdecl', '_rawobject', 'flags',
                'finalizer_registered']
-    _immutable_fields_ = ["cppclass", "isref"]
+    _immutable_fields_ = ['clsdecl']
 
     finalizer_registered = False
 
-    def __init__(self, space, cppclass, rawobject, isref, python_owns):
+    def __init__(self, space, decl, rawobject, isref, python_owns):
         self.space = space
-        self.cppclass = cppclass
+        self.clsdecl = decl
         assert lltype.typeOf(rawobject) == capi.C_OBJECT
         assert not isref or rawobject
         self._rawobject = rawobject
         assert not isref or not python_owns
-        self.isref = isref
-        self.python_owns = python_owns
-        self._opt_register_finalizer()
+        self.flags = 0
+        if isref:
+            self.flags |= INSTANCE_FLAGS_IS_REF
+        if python_owns:
+            self.flags |= INSTANCE_FLAGS_PYTHON_OWNS
+            self._opt_register_finalizer()
 
     def _opt_register_finalizer(self):
-        if self.python_owns and not self.finalizer_registered \
-               and not hasattr(self.space, "fake"):
+        if not self.finalizer_registered and not hasattr(self.space, "fake"):
+            assert self.flags & INSTANCE_FLAGS_PYTHON_OWNS
             self.register_finalizer(self.space)
             self.finalizer_registered = True
 
     def _nullcheck(self):
-        if not self._rawobject or (self.isref and not self.get_rawobject()):
+        if not self._rawobject or \
+               ((self.flags & INSTANCE_FLAGS_IS_REF) and not 
self.get_rawobject()):
             raise oefmt(self.space.w_ReferenceError,
                         "trying to access a NULL pointer")
 
     # allow user to determine ownership rules on a per object level
     def fget_python_owns(self, space):
-        return space.newbool(self.python_owns)
+        return space.newbool(bool(self.flags & INSTANCE_FLAGS_PYTHON_OWNS))
 
     @unwrap_spec(value=bool)
     def fset_python_owns(self, space, value):
-        self.python_owns = space.is_true(value)
-        self._opt_register_finalizer()
+        if space.is_true(value):
+            self.flags |= INSTANCE_FLAGS_PYTHON_OWNS
+            self._opt_register_finalizer()
+        else:
+            self.flags &= ~INSTANCE_FLAGS_PYTHON_OWNS
 
     def get_cppthis(self, calling_scope):
-        return self.cppclass.get_cppthis(self, calling_scope)
+        return self.clsdecl.get_cppthis(self, calling_scope)
 
     def get_rawobject(self):
-        if not self.isref:
+        if not (self.flags & INSTANCE_FLAGS_IS_REF):
             return self._rawobject
         else:
             ptrptr = rffi.cast(rffi.VOIDPP, self._rawobject)
@@ -1078,12 +1096,9 @@
         return None
 
     def instance__init__(self, args_w):
-        if capi.c_is_abstract(self.space, self.cppclass.handle):
-            raise oefmt(self.space.w_TypeError,
-                        "cannot instantiate abstract class '%s'",
-                        self.cppclass.name)
-        constructor_overload = self.cppclass.get_overload(self.cppclass.name)
-        constructor_overload.call(self, args_w)
+        raise oefmt(self.space.w_TypeError,
+                    "cannot instantiate abstract class '%s'",
+                    self.clsdecl.name)
  
     def instance__eq__(self, w_other):
         # special case: if other is None, compare pointer-style
@@ -1099,7 +1114,7 @@
             for name in ["", "__gnu_cxx", "__1"]:
                 nss = scope_byname(self.space, name)
                 meth_idx = capi.c_get_global_operator(
-                    self.space, nss, self.cppclass, other.cppclass, 
"operator==")
+                    self.space, nss, self.clsdecl, other.clsdecl, "operator==")
                 if meth_idx != -1:
                     f = nss._make_cppfunction("operator==", meth_idx)
                     ol = W_CPPOverload(self.space, nss, [f])
@@ -1118,14 +1133,15 @@
         # fallback 2: direct pointer comparison (the class comparison is 
needed since
         # the first data member in a struct and the struct have the same 
address)
         other = self.space.interp_w(W_CPPClass, w_other, can_be_None=False)  # 
TODO: factor out
-        iseq = (self._rawobject == other._rawobject) and (self.cppclass == 
other.cppclass)
+        iseq = (self._rawobject == other._rawobject) and (self.clsdecl == 
other.clsdecl)
         return self.space.newbool(iseq)
 
     def instance__ne__(self, w_other):
         return self.space.not_(self.instance__eq__(w_other))
 
     def instance__nonzero__(self):
-        if not self._rawobject or (self.isref and not self.get_rawobject()):
+        if not self._rawobject or \
+               ((self.flags & INSTANCE_FLAGS_IS_REF) and not 
self.get_rawobject()):
             return self.space.w_False
         return self.space.w_True
 
@@ -1134,36 +1150,35 @@
         if w_as_builtin is not None:
             return self.space.len(w_as_builtin)
         raise oefmt(self.space.w_TypeError,
-                    "'%s' has no length", self.cppclass.name)
+                    "'%s' has no length", self.clsdecl.name)
 
     def instance__cmp__(self, w_other):
         w_as_builtin = self._get_as_builtin()
         if w_as_builtin is not None:
             return self.space.cmp(w_as_builtin, w_other)
         raise oefmt(self.space.w_AttributeError,
-                    "'%s' has no attribute __cmp__", self.cppclass.name)
+                    "'%s' has no attribute __cmp__", self.clsdecl.name)
 
     def instance__repr__(self):
         w_as_builtin = self._get_as_builtin()
         if w_as_builtin is not None:
             return self.space.repr(w_as_builtin)
         return self.space.newtext("<%s object at 0x%x>" %
-                               (self.cppclass.name, rffi.cast(rffi.ULONG, 
self.get_rawobject())))
+                               (self.clsdecl.name, rffi.cast(rffi.ULONG, 
self.get_rawobject())))
 
     def destruct(self):
-        if self._rawobject and not self.isref:
+        if self._rawobject and not (self.flags & INSTANCE_FLAGS_IS_REF):
             memory_regulator.unregister(self)
-            capi.c_destruct(self.space, self.cppclass, self._rawobject)
+            capi.c_destruct(self.space, self.clsdecl, self._rawobject)
             self._rawobject = capi.C_NULL_OBJECT
 
     def _finalize_(self):
-        if self.python_owns:
+        if self.flags & INSTANCE_FLAGS_PYTHON_OWNS:
             self.destruct()
 
 W_CPPClass.typedef = TypeDef(
     'CPPClass',
-    cppclass = interp_attrproperty_w('cppclass', cls=W_CPPClass),
-    _python_owns = GetSetProperty(W_CPPClass.fget_python_owns, 
W_CPPClass.fset_python_owns),
+    __python_owns__ = GetSetProperty(W_CPPClass.fget_python_owns, 
W_CPPClass.fset_python_owns),
     __init__ = interp2app(W_CPPClass.instance__init__),
     __eq__ = interp2app(W_CPPClass.instance__eq__),
     __ne__ = interp2app(W_CPPClass.instance__ne__),
@@ -1220,21 +1235,21 @@
     state = space.fromcache(State)
     return space.call_function(state.w_fngen_callback, w_callable, 
space.newint(npar))
 
-def wrap_cppobject(space, rawobject, cppclass,
-                   do_cast=True, python_owns=False, is_ref=False, fresh=False):
+def wrap_cppinstance(space, rawobject, clsdecl,
+                     do_cast=True, python_owns=False, is_ref=False, 
fresh=False):
     rawobject = rffi.cast(capi.C_OBJECT, rawobject)
 
     # cast to actual if requested and possible
     w_pycppclass = None
     if do_cast and rawobject:
-        actual = capi.c_actual_class(space, cppclass, rawobject)
-        if actual != cppclass.handle:
+        actual = capi.c_actual_class(space, clsdecl, rawobject)
+        if actual != clsdecl.handle:
             try:
                 w_pycppclass = get_pythonized_cppclass(space, actual)
-                offset = capi.c_base_offset1(space, actual, cppclass, 
rawobject, -1)
+                offset = capi.c_base_offset1(space, actual, clsdecl, 
rawobject, -1)
                 rawobject = capi.direct_ptradd(rawobject, offset)
-                w_cppclass = space.findattr(w_pycppclass, 
space.newtext("__cppdecl__"))
-                cppclass = space.interp_w(W_CPPClassDecl, w_cppclass, 
can_be_None=False)
+                w_cppdecl = space.findattr(w_pycppclass, 
space.newtext("__cppdecl__"))
+                clsdecl = space.interp_w(W_CPPClassDecl, w_cppdecl, 
can_be_None=False)
             except Exception:
                 # failed to locate/build the derived class, so stick to the 
base (note
                 # that only get_pythonized_cppclass is expected to raise, so 
none of
@@ -1242,18 +1257,18 @@
                 pass
 
     if w_pycppclass is None:
-        w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
+        w_pycppclass = get_pythonized_cppclass(space, clsdecl.handle)
 
     # try to recycle existing object if this one is not newly created
     if not fresh and rawobject:
         obj = memory_regulator.retrieve(rawobject)
-        if obj is not None and obj.cppclass is cppclass:
+        if obj is not None and obj.clsdecl is clsdecl:
             return obj
 
     # fresh creation
     w_cppinstance = space.allocate_instance(W_CPPClass, w_pycppclass)
     cppinstance = space.interp_w(W_CPPClass, w_cppinstance, can_be_None=False)
-    cppinstance.__init__(space, cppclass, rawobject, is_ref, python_owns)
+    cppinstance.__init__(space, clsdecl, rawobject, is_ref, python_owns)
     memory_regulator.register(cppinstance)
     return w_cppinstance
 
@@ -1264,7 +1279,7 @@
     except TypeError:
         pass
     # attempt to get address of C++ instance
-    return rffi.cast(rffi.INTPTR_T, converter.get_rawobject(space, w_obj))
+    return rffi.cast(rffi.INTPTR_T, converter.get_rawobject(space, w_obj, 
False))
 
 @unwrap_spec(w_obj=W_Root)
 def addressof(space, w_obj):
@@ -1273,19 +1288,30 @@
     return space.newlong(address)
 
 @unwrap_spec(owns=bool, cast=bool)
-def bind_object(space, w_obj, w_pycppclass, owns=False, cast=False):
-    """Takes an address and a bound C++ class proxy, returns a bound 
instance."""
+def _bind_object(space, w_obj, w_clsdecl, owns=False, cast=False):
     try:
         # attempt address from array or C++ instance
         rawobject = rffi.cast(capi.C_OBJECT, _addressof(space, w_obj))
     except Exception:
         # accept integer value as address
         rawobject = rffi.cast(capi.C_OBJECT, space.uint_w(w_obj))
-    w_cppclass = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
-    if not w_cppclass:
-        w_cppclass = scope_byname(space, space.text_w(w_pycppclass))
-        if not w_cppclass:
+    decl = space.interp_w(W_CPPClassDecl, w_clsdecl, can_be_None=False)
+    return wrap_cppinstance(space, rawobject, decl, python_owns=owns, 
do_cast=cast)
+
+@unwrap_spec(owns=bool, cast=bool)
+def bind_object(space, w_obj, w_pycppclass, owns=False, cast=False):
+    """Takes an address and a bound C++ class proxy, returns a bound 
instance."""
+    w_clsdecl = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
+    if not w_clsdecl:
+        w_clsdecl = scope_byname(space, space.text_w(w_pycppclass))
+        if not w_clsdecl:
             raise oefmt(space.w_TypeError,
                         "no such class: %s", space.text_w(w_pycppclass))
-    cppclass = space.interp_w(W_CPPClassDecl, w_cppclass, can_be_None=False)
-    return wrap_cppobject(space, rawobject, cppclass, do_cast=cast, 
python_owns=owns)
+    return _bind_object(space, w_obj, w_clsdecl, owns, cast)
+
+def move(space, w_obj):
+    """Casts the given instance into an C++-style rvalue."""
+    obj = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
+    if obj:
+        obj.flags |= INSTANCE_FLAGS_IS_R_VALUE
+    return w_obj
diff --git a/pypy/module/_cppyy/pythonify.py b/pypy/module/_cppyy/pythonify.py
--- a/pypy/module/_cppyy/pythonify.py
+++ b/pypy/module/_cppyy/pythonify.py
@@ -10,7 +10,7 @@
 class CPPMetaScope(type):
     def __getattr__(self, name):
         try:
-            return get_pycppitem(self, name)  # will cache on self
+            return get_scoped_pycppitem(self, name)  # will cache on self
         except Exception as e:
             raise AttributeError("%s object has no attribute '%s' (details: 
%s)" %
                                  (self, name, str(e)))
@@ -36,11 +36,14 @@
             self._scope = scope
 
     def _arg_to_str(self, arg):
-        if arg == str:
-            import _cppyy
-            arg = _cppyy._std_string_name()
-        elif type(arg) != str:
-            arg = arg.__name__
+        try:
+            arg = arg.__cppname__
+        except AttributeError:
+            if arg == str:
+                import _cppyy
+                arg = _cppyy._std_string_name()
+            elif type(arg) != str:
+                arg = arg.__name__
         return arg
 
     def __call__(self, *args):
@@ -58,8 +61,36 @@
         return self.__call__(*args)
 
 
-def clgen_callback(name):
-    return get_pycppclass(name)
+def scope_splitter(name):
+    is_open_template, scope = 0, ""
+    for c in name:
+        if c == ':' and not is_open_template:
+            if scope:
+                yield scope
+                scope = ""
+            continue
+        elif c == '<':
+            is_open_template += 1
+        elif c == '>':
+            is_open_template -= 1
+        scope += c
+    yield scope
+
+def get_pycppitem(final_scoped_name):
+    # walk scopes recursively down from global namespace ("::") to get the
+    # actual (i.e. not typedef'ed) class, triggering all necessary creation
+    scope = gbl
+    for name in scope_splitter(final_scoped_name):
+        scope = getattr(scope, name)
+    return scope
+get_pycppclass = get_pycppitem     # currently no distinction, but might
+                                   # in future for performance
+
+
+# callbacks (originating from interp_cppyy.py) to allow interp-level to
+# initiate creation of app-level classes and function
+def clgen_callback(final_scoped_name):
+    return get_pycppclass(final_scoped_name)
 
 def fngen_callback(func, npar): # todo, some kind of arg transform spec
     if npar == 0:
@@ -75,20 +106,19 @@
         return wrapper
 
 
+# construction of namespaces and classes, and their helpers
+def make_module_name(scope):
+    if scope:
+        return scope.__module__ + '.' + scope.__name__
+    return 'cppyy'
+
 def make_static_function(func_name, cppol):
     def function(*args):
         return cppol.call(None, *args)
     function.__name__ = func_name
-    function.__doc__ = cppol.signature()
+    function.__doc__ = cppol.prototype()
     return staticmethod(function)
 
-def make_method(meth_name, cppol):
-    def method(self, *args):
-        return cppol.call(self, *args)
-    method.__name__ = meth_name
-    method.__doc__ = cppol.signature()
-    return method
-
 
 def make_cppnamespace(scope, name, decl):
     # build up a representation of a C++ namespace (namespaces are classes)
@@ -98,20 +128,19 @@
     ns_meta = type(name+'_meta', (CPPMetaNamespace,), {})
 
     # create the python-side C++ namespace representation, cache in scope if 
given
-    d = {"__cppdecl__" : decl, "__cppname__" : decl.__cppname__ }
+    d = {"__cppdecl__" : decl,
+         "__module__" : make_module_name(scope),
+         "__cppname__" : decl.__cppname__ }
     pyns = ns_meta(name, (CPPNamespace,), d)
     if scope:
         setattr(scope, name, pyns)
 
     # install as modules to allow importing from (note naming: cppyy)
-    modname = 'cppyy.gbl'
-    if scope:
-        modname = 'cppyy.gbl.'+pyns.__cppname__.replace('::', '.')
-    sys.modules[modname] = pyns
+    sys.modules[make_module_name(pyns)] = pyns
     return pyns
 
 def _drop_cycles(bases):
-    # TODO: figure this out, as it seems to be a PyPy bug?!
+    # TODO: figure out why this is necessary?
     for b1 in bases:
         for b2 in bases:
             if not (b1 is b2) and issubclass(b2, b1):
@@ -119,27 +148,37 @@
                 break
     return tuple(bases)
 
-def make_new(class_name):
+
+def make_new(decl):
     def __new__(cls, *args):
         # create a place-holder only as there may be a derived class defined
+        # TODO: get rid of the import and add user-land bind_object that uses
+        # _bind_object (see interp_cppyy.py)
         import _cppyy
-        instance = _cppyy.bind_object(0, class_name, True)
+        instance = _cppyy._bind_object(0, decl, True)
         if not instance.__class__ is cls:
             instance.__class__ = cls     # happens for derived class
         return instance
     return __new__
 
-def make_cppclass(scope, class_name, final_class_name, decl):
+def make_method(meth_name, cppol):
+    def method(self, *args):
+        return cppol.call(self, *args)
+    method.__name__ = meth_name
+    method.__doc__ = cppol.prototype()
+    return method
+
+def make_cppclass(scope, cl_name, decl):
 
     # get a list of base classes for class creation
     bases = [get_pycppclass(base) for base in decl.get_base_names()]
     if not bases:
         bases = [CPPClass,]
     else:
-        # it's technically possible that the required class now has been built
-        # if one of the base classes uses it in e.g. a function interface
+        # it's possible that the required class now has been built if one of
+        # the base classes uses it in e.g. a function interface
         try:
-            return scope.__dict__[final_class_name]
+            return scope.__dict__[cl_name]
         except KeyError:
             pass
 
@@ -147,39 +186,41 @@
     d_meta = {}
 
     # prepare dictionary for python-side C++ class representation
-    def dispatch(self, name, signature):
-        cppol = decl.dispatch(name, signature)
-        return types.MethodType(make_method(name, cppol), self, type(self))
+    def dispatch(self, m_name, signature):
+        cppol = decl.__dispatch__(m_name, signature)
+        return types.MethodType(make_method(m_name, cppol), self, type(self))
     d_class = {"__cppdecl__"   : decl,
+         "__new__"      : make_new(decl),
+         "__module__"   : make_module_name(scope),
          "__cppname__"  : decl.__cppname__,
-         "__new__"      : make_new(class_name),
+         "__dispatch__" : dispatch,
          }
 
     # insert (static) methods into the class dictionary
-    for name in decl.get_method_names():
-        cppol = decl.get_overload(name)
+    for m_name in decl.get_method_names():
+        cppol = decl.get_overload(m_name)
         if cppol.is_static():
-            d_class[name] = make_static_function(name, cppol)
+            d_class[m_name] = make_static_function(m_name, cppol)
         else:
-            d_class[name] = make_method(name, cppol)
+            d_class[m_name] = make_method(m_name, cppol)
 
     # add all data members to the dictionary of the class to be created, and
     # static ones also to the metaclass (needed for property setters)
-    for name in decl.get_datamember_names():
-        cppdm = decl.get_datamember(name)
-        d_class[name] = cppdm
+    for d_name in decl.get_datamember_names():
+        cppdm = decl.get_datamember(d_name)
+        d_class[d_name] = cppdm
         if cppdm.is_static():
-            d_meta[name] = cppdm
+            d_meta[d_name] = cppdm
 
     # create a metaclass to allow properties (for static data write access)
     metabases = [type(base) for base in bases]
-    metacpp = type(CPPMetaScope)(class_name+'_meta', _drop_cycles(metabases), 
d_meta)
+    metacpp = type(CPPMetaScope)(cl_name+'_meta', _drop_cycles(metabases), 
d_meta)
 
     # create the python-side C++ class
-    pycls = metacpp(class_name, _drop_cycles(bases), d_class)
+    pycls = metacpp(cl_name, _drop_cycles(bases), d_class)
 
     # store the class on its outer scope
-    setattr(scope, final_class_name, pycls)
+    setattr(scope, cl_name, pycls)
 
     # the call to register will add back-end specific pythonizations and thus
     # needs to run first, so that the generic pythonizations can use them
@@ -192,32 +233,32 @@
     return CPPTemplate(template_name, scope)
 
 
-def get_pycppitem(scope, name):
+def get_scoped_pycppitem(scope, name):
     import _cppyy
 
-    # resolve typedefs/aliases
-    full_name = (scope == gbl) and name or (scope.__name__+'::'+name)
-    true_name = _cppyy._resolve_name(full_name)
-    if true_name != full_name:
-        return get_pycppclass(true_name)
+    # resolve typedefs/aliases: these may cross namespaces, in which case
+    # the lookup must trigger the creation of all necessary scopes
+    scoped_name = (scope == gbl) and name or (scope.__cppname__+'::'+name)
+    final_scoped_name = _cppyy._resolve_name(scoped_name)
+    if final_scoped_name != scoped_name:
+        pycppitem = get_pycppitem(final_scoped_name)
+        # also store on the requested scope (effectively a typedef or pointer 
copy)
+        setattr(scope, name, pycppitem)
+        return pycppitem
 
     pycppitem = None
 
-    # classes
-    cppitem = _cppyy._scope_byname(true_name)
+    # scopes (classes and namespaces)
+    cppitem = _cppyy._scope_byname(final_scoped_name)
     if cppitem:
-        name = true_name
-        if scope != gbl:
-            name = true_name[len(scope.__cppname__)+2:]
         if cppitem.is_namespace():
             pycppitem = make_cppnamespace(scope, name, cppitem)
-            setattr(scope, name, pycppitem)
         else:
-            pycppitem = make_cppclass(scope, name, true_name, cppitem)
+            pycppitem = make_cppclass(scope, name, cppitem)
 
     # templates
     if not cppitem:
-        cppitem = _cppyy._template_byname(true_name)
+        cppitem = _cppyy._is_template(final_scoped_name)
         if cppitem:
             pycppitem = make_cpptemplatetype(scope, name)
             setattr(scope, name, pycppitem)
@@ -249,29 +290,6 @@
     raise AttributeError("'%s' has no attribute '%s'" % (str(scope), name))
 
 
-def scope_splitter(name):
-    is_open_template, scope = 0, ""
-    for c in name:
-        if c == ':' and not is_open_template:
-            if scope:
-                yield scope
-                scope = ""
-            continue
-        elif c == '<':
-            is_open_template += 1
-        elif c == '>':
-            is_open_template -= 1
-        scope += c
-    yield scope
-
-def get_pycppclass(name):
-    # break up the name, to walk the scopes and get the class recursively
-    scope = gbl
-    for part in scope_splitter(name):
-        scope = getattr(scope, part)
-    return scope
-
-
 # pythonization by decoration (move to their own file?)
 def python_style_getitem(self, idx):
     # python-style indexing: check for size and allow indexing from the back
@@ -346,8 +364,8 @@
     # also the fallback on the indexed __getitem__, but that is slower)
     if not 'vector' in pyclass.__name__[:11] and \
             ('begin' in pyclass.__dict__ and 'end' in pyclass.__dict__):
-        if _cppyy._scope_byname(pyclass.__name__+'::iterator') or \
-                _cppyy._scope_byname(pyclass.__name__+'::const_iterator'):
+        if _cppyy._scope_byname(pyclass.__cppname__+'::iterator') or \
+                _cppyy._scope_byname(pyclass.__cppname__+'::const_iterator'):
             def __iter__(self):
                 i = self.begin()
                 while i != self.end():
@@ -416,17 +434,21 @@
     # pre-create std to allow direct importing
     gbl.std = make_cppnamespace(gbl, 'std', _cppyy._scope_byname('std'))
 
+    # add move cast
+    gbl.std.move = _cppyy.move
+
     # install a type for enums to refer to
     # TODO: this is correct for C++98, not for C++11 and in general there will
     # be the same issue for all typedef'd builtin types
     setattr(gbl, 'internal_enum_type_t', int)
 
-    # install nullptr as a unique reference
-    setattr(gbl, 'nullptr', _cppyy._get_nullptr())
-
     # install for user access
     _cppyy.gbl = gbl
 
+    # install nullptr as a unique reference
+    _cppyy.nullptr = _cppyy._get_nullptr()
+
+
 # user-defined pythonizations interface
 _pythonizations = {}
 def add_pythonization(class_name, callback):
diff --git a/pypy/module/_cppyy/src/dummy_backend.cxx 
b/pypy/module/_cppyy/src/dummy_backend.cxx
--- a/pypy/module/_cppyy/src/dummy_backend.cxx
+++ b/pypy/module/_cppyy/src/dummy_backend.cxx
@@ -955,7 +955,13 @@
     return cppstring_to_cstring("");
 }
 
-char* cppyy_method_signature(cppyy_scope_t /* handle */, cppyy_index_t /* 
method_index */) {
+char* cppyy_method_signature(
+        cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /* 
show_formalargs */) {
+    return cppstring_to_cstring("");
+}
+
+char* cppyy_method_prototype(
+        cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /* 
show_formalargs */) {
     return cppstring_to_cstring("");
 }
 
diff --git a/pypy/module/_cppyy/test/Makefile b/pypy/module/_cppyy/test/Makefile
--- a/pypy/module/_cppyy/test/Makefile
+++ b/pypy/module/_cppyy/test/Makefile
@@ -1,12 +1,14 @@
 dicts = advancedcppDict.so \
         advancedcpp2Dict.so \
+        cpp11featuresDict.so \
         crossingDict.so \
         datatypesDict.so \
         example01Dict.so \
         fragileDict.so \
         operatorsDict.so \
         overloadsDict.so \
-        stltypesDict.so
+        stltypesDict.so \
+        templatesDict.so
 
 all : $(dicts)
 
diff --git a/pypy/module/_cppyy/test/advancedcpp.cxx 
b/pypy/module/_cppyy/test/advancedcpp.cxx
--- a/pypy/module/_cppyy/test/advancedcpp.cxx
+++ b/pypy/module/_cppyy/test/advancedcpp.cxx
@@ -106,17 +106,6 @@
 }
 
 
-// more template testing
-long my_templated_method_class::get_size() { return -1; }
-
-long my_templated_method_class::get_char_size()   { return (long)sizeof(char); 
}
-long my_templated_method_class::get_int_size()    { return (long)sizeof(int); }
-long my_templated_method_class::get_long_size()   { return (long)sizeof(long); 
}
-long my_templated_method_class::get_float_size()  { return 
(long)sizeof(float); }
-long my_templated_method_class::get_double_size() { return 
(long)sizeof(double); }
-long my_templated_method_class::get_self_size()   { return 
(long)sizeof(my_templated_method_class); }
-
-
 // overload order testing
 int overload_one_way::gime() const { return 1; }
 std::string overload_one_way::gime() { return "aap"; }
diff --git a/pypy/module/_cppyy/test/advancedcpp.h 
b/pypy/module/_cppyy/test/advancedcpp.h
--- a/pypy/module/_cppyy/test/advancedcpp.h
+++ b/pypy/module/_cppyy/test/advancedcpp.h
@@ -246,8 +246,6 @@
     int m_i;
 };
 
-template class std::vector<ref_tester>;
-
 
 //===========================================================================
 class some_convertible {           // for math conversions testing
@@ -275,6 +273,7 @@
 extern double my_global_double;    // a couple of globals for access testing
 extern double my_global_array[500];
 extern double* my_global_ptr;
+static const char my_global_string[] = "aap " " noot " " mies";
 
 //===========================================================================
 class some_class_with_data {       // for life-line and identity testing
@@ -387,37 +386,6 @@
 template char my_templated_function<char>(char);
 template double my_templated_function<double>(double);
 
-class my_templated_method_class {
-public:
-    long get_size();      // to get around bug in genreflex
-    template<class B> long get_size();
-
-    long get_char_size();
-    long get_int_size();
-    long get_long_size();
-    long get_float_size();
-    long get_double_size();
-
-    long get_self_size();
-
-private:
-    double m_data[3];
-};
-
-template<class B>
-inline long my_templated_method_class::get_size() {
-    return sizeof(B);
-}
-
-template long my_templated_method_class::get_size<char>();
-template long my_templated_method_class::get_size<int>();
-template long my_templated_method_class::get_size<long>();
-template long my_templated_method_class::get_size<float>();
-template long my_templated_method_class::get_size<double>();
-
-typedef my_templated_method_class my_typedef_t;
-template long my_templated_method_class::get_size<my_typedef_t>();
-
 
 //===========================================================================
 class overload_one_way {           // overload order testing
diff --git a/pypy/module/_cppyy/test/advancedcpp.xml 
b/pypy/module/_cppyy/test/advancedcpp.xml
--- a/pypy/module/_cppyy/test/advancedcpp.xml
+++ b/pypy/module/_cppyy/test/advancedcpp.xml
@@ -53,8 +53,6 @@
   <class name="std::vector<float>" />
   <class pattern="my_templated_class<*>" />
   <function pattern="my_templated_function<*>" />
-  <class name="my_templated_method_class" />
-  <class name="my_typedef_t" />
 
   <class name="overload_one_way" />
   <class name="overload_the_other_way" />
diff --git a/pypy/module/_cppyy/test/cpp11features.cxx 
b/pypy/module/_cppyy/test/cpp11features.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/test/cpp11features.cxx
@@ -0,0 +1,18 @@
+#if __cplusplus >= 201103L
+
+#include "cpp11features.h"
+
+
+// for std::shared_ptr<> testing
+int TestSharedPtr::s_counter = 0;
+
+std::shared_ptr<TestSharedPtr> create_shared_ptr_instance() {
+    return std::shared_ptr<TestSharedPtr>(new TestSharedPtr);
+}
+
+
+// for move ctors etc.
+int TestMoving1::s_move_counter = 0;
+int TestMoving2::s_move_counter = 0;
+
+#endif // c++11 and later
diff --git a/pypy/module/_cppyy/test/cpp11features.h 
b/pypy/module/_cppyy/test/cpp11features.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/test/cpp11features.h
@@ -0,0 +1,45 @@
+#if __cplusplus >= 201103L
+
+#include <memory>
+
+
+//===========================================================================
+class TestSharedPtr {        // for std::shared_ptr<> testing
+public:
+    static int s_counter;
+
+public:
+    TestSharedPtr() { ++s_counter; }
+    TestSharedPtr(const TestSharedPtr&) { ++s_counter; }
+    ~TestSharedPtr() { --s_counter; }
+};
+
+std::shared_ptr<TestSharedPtr> create_shared_ptr_instance();
+
+
+//===========================================================================
+class TestMoving1 {          // for move ctors etc.
+public:
+    static int s_move_counter;
+
+public:
+    TestMoving1() {}
+    TestMoving1(TestMoving1&&) { ++s_move_counter; }
+    TestMoving1(const TestMoving1&) {}
+    TestMoving1& operator=(TestMoving1&&) { ++s_move_counter; return *this; }
+    TestMoving1& operator=(TestMoving1&) { return *this; }
+};
+
+class TestMoving2 {          // note opposite method order from TestMoving1
+public:
+    static int s_move_counter;
+
+public:
+    TestMoving2() {}
+    TestMoving2(const TestMoving2&) {}
+    TestMoving2(TestMoving2&& other) { ++s_move_counter; }
+    TestMoving2& operator=(TestMoving2&) { return *this; }
+    TestMoving2& operator=(TestMoving2&&) { ++s_move_counter; return *this; }
+};
+
+#endif // c++11 and later
diff --git a/pypy/module/_cppyy/test/cpp11features.xml 
b/pypy/module/_cppyy/test/cpp11features.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/test/cpp11features.xml
@@ -0,0 +1,6 @@
+<lcgdict>
+
+  <class name="TestSharedPtr" />
+  <class pattern="TestMoving*" />
+
+</lcgdict>
diff --git a/pypy/module/_cppyy/test/fragile.h 
b/pypy/module/_cppyy/test/fragile.h
--- a/pypy/module/_cppyy/test/fragile.h
+++ b/pypy/module/_cppyy/test/fragile.h
@@ -30,9 +30,11 @@
     void overload(int, no_such_class* p = 0) {}
 };
 
+static const int dummy_location = 0xdead;
+
 class E {
 public:
-    E() : m_pp_no_such(0), m_pp_a(0) {}
+    E() : m_pp_no_such((no_such_class**)&dummy_location), m_pp_a(0) {}
 
     virtual int check() { return (int)'E'; }
     void overload(no_such_class**) {}
diff --git a/pypy/module/_cppyy/test/templates.cxx 
b/pypy/module/_cppyy/test/templates.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/test/templates.cxx
@@ -0,0 +1,12 @@
+#include "templates.h"
+
+
+// template methods
+long MyTemplatedMethodClass::get_size() { return -1; }
+
+long MyTemplatedMethodClass::get_char_size()   { return (long)sizeof(char); }
+long MyTemplatedMethodClass::get_int_size()    { return (long)sizeof(int); }
+long MyTemplatedMethodClass::get_long_size()   { return (long)42; /* "lying" 
*/ }
+long MyTemplatedMethodClass::get_float_size()  { return (long)sizeof(float); }
+long MyTemplatedMethodClass::get_double_size() { return (long)sizeof(double); }
+long MyTemplatedMethodClass::get_self_size()   { return 
(long)sizeof(MyTemplatedMethodClass); }
diff --git a/pypy/module/_cppyy/test/templates.h 
b/pypy/module/_cppyy/test/templates.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/test/templates.h
@@ -0,0 +1,35 @@
+//===========================================================================
+class MyTemplatedMethodClass {         // template methods
+public:
+    long get_size();      // to get around bug in genreflex
+    template<class B> long get_size();
+
+    long get_char_size();
+    long get_int_size();
+    long get_long_size();
+    long get_float_size();
+    long get_double_size();
+
+    long get_self_size();
+
+private:
+    double m_data[3];
+};
+
+template<class B>
+inline long MyTemplatedMethodClass::get_size() {
+    return sizeof(B);
+}
+
+//
+typedef MyTemplatedMethodClass MyTMCTypedef_t;
+
+// explicit instantiation
+template long MyTemplatedMethodClass::get_size<char>();
+template long MyTemplatedMethodClass::get_size<int>();
+
+// "lying" specialization
+template<>
+inline long MyTemplatedMethodClass::get_size<long>() {
+    return 42;
+}
diff --git a/pypy/module/_cppyy/test/templates.xml 
b/pypy/module/_cppyy/test/templates.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/test/templates.xml
@@ -0,0 +1,6 @@
+<lcgdict>
+
+  <class name="MyTemplatedMethodClass" />
+  <class name="MyTMCTypedef_t" />
+
+</lcgdict>
diff --git a/pypy/module/_cppyy/test/test_advancedcpp.py 
b/pypy/module/_cppyy/test/test_advancedcpp.py
--- a/pypy/module/_cppyy/test/test_advancedcpp.py
+++ b/pypy/module/_cppyy/test/test_advancedcpp.py
@@ -28,9 +28,9 @@
     def test01_default_arguments(self):
         """Test usage of default arguments"""
 
-        import _cppyy
+        import _cppyy as cppyy
         def test_defaulter(n, t):
-            defaulter = getattr(_cppyy.gbl, '%s_defaulter' % n)
+            defaulter = getattr(cppyy.gbl, '%s_defaulter' % n)
 
             d = defaulter()
             assert d.m_a == t(11)
@@ -55,23 +55,23 @@
             assert d.m_b ==  t(4)
             assert d.m_c ==  t(5)
             d.__destruct__()
-        test_defaulter('short', int)
+        test_defaulter('short',  int)
         test_defaulter('ushort', int)
-        test_defaulter('int', int)
-        test_defaulter('uint', int)
-        test_defaulter('long', long)
-        test_defaulter('ulong', long)
-        test_defaulter('llong', long)
+        test_defaulter('int',    int)
+        test_defaulter('uint',   int)
+        test_defaulter('long',   long)
+        test_defaulter('ulong',  long)
+        test_defaulter('llong',  long)
         test_defaulter('ullong', long)
-        test_defaulter('float', float)
+        test_defaulter('float',  float)
         test_defaulter('double', float)
 
     def test02_simple_inheritance(self):
         """Test binding of a basic inheritance structure"""
 
-        import _cppyy
-        base_class    = _cppyy.gbl.base_class
-        derived_class = _cppyy.gbl.derived_class
+        import _cppyy as cppyy
+        base_class    = cppyy.gbl.base_class
+        derived_class = cppyy.gbl.derived_class
 
         assert issubclass(derived_class, base_class)
         assert not issubclass(base_class, derived_class)
@@ -123,8 +123,8 @@
     def test03_namespaces(self):
         """Test access to namespaces and inner classes"""
 
-        import _cppyy
-        gbl = _cppyy.gbl
+        import _cppyy as cppyy
+        gbl = cppyy.gbl
 
         assert gbl.a_ns      is gbl.a_ns
         assert gbl.a_ns.d_ns is gbl.a_ns.d_ns
@@ -150,8 +150,8 @@
     def test03a_namespace_lookup_on_update(self):
         """Test whether namespaces can be shared across dictionaries."""
 
-        import _cppyy, ctypes
-        gbl = _cppyy.gbl
+        import _cppyy as cppyy, ctypes
+        gbl = cppyy.gbl
 
         lib2 = ctypes.CDLL("./advancedcpp2Dict.so", ctypes.RTLD_GLOBAL)
 
@@ -179,8 +179,8 @@
     def test04_template_types(self):
         """Test bindings of templated types"""
 
-        import _cppyy
-        gbl = _cppyy.gbl
+        import _cppyy as cppyy
+        gbl = cppyy.gbl
 
         assert gbl.T1 is gbl.T1
         assert gbl.T2 is gbl.T2
@@ -245,8 +245,8 @@
     def test05_abstract_classes(self):
         """Test non-instatiatability of abstract classes"""
 
-        import _cppyy
-        gbl = _cppyy.gbl
+        import _cppyy as cppyy
+        gbl = cppyy.gbl
 
         raises(TypeError, gbl.a_class)
         raises(TypeError, gbl.some_abstract_class)
@@ -260,12 +260,12 @@
     def test06_datamembers(self):
         """Test data member access when using virtual inheritence"""
 
-        import _cppyy
-        a_class   = _cppyy.gbl.a_class
-        b_class   = _cppyy.gbl.b_class
-        c_class_1 = _cppyy.gbl.c_class_1
-        c_class_2 = _cppyy.gbl.c_class_2
-        d_class   = _cppyy.gbl.d_class
+        import _cppyy as cppyy
+        a_class   = cppyy.gbl.a_class
+        b_class   = cppyy.gbl.b_class
+        c_class_1 = cppyy.gbl.c_class_1
+        c_class_2 = cppyy.gbl.c_class_2
+        d_class   = cppyy.gbl.d_class
 
         assert issubclass(b_class, a_class)
         assert issubclass(c_class_1, a_class)
@@ -354,8 +354,8 @@
     def test07_pass_by_reference(self):
         """Test reference passing when using virtual inheritance"""
 
-        import _cppyy
-        gbl = _cppyy.gbl
+        import _cppyy as cppyy
+        gbl = cppyy.gbl
         b_class = gbl.b_class
         c_class = gbl.c_class_2
         d_class = gbl.d_class
@@ -387,71 +387,75 @@
     def test08_void_pointer_passing(self):
         """Test passing of variants of void pointer arguments"""
 
-        import _cppyy
-        pointer_pass        = _cppyy.gbl.pointer_pass
-        some_concrete_class = _cppyy.gbl.some_concrete_class
+        import _cppyy as cppyy
+        pointer_pass        = cppyy.gbl.pointer_pass
+        some_concrete_class = cppyy.gbl.some_concrete_class
 
         pp = pointer_pass()
         o = some_concrete_class()
 
-        assert _cppyy.addressof(o) == pp.gime_address_ptr(o)
-        assert _cppyy.addressof(o) == pp.gime_address_ptr_ptr(o)
-        assert _cppyy.addressof(o) == pp.gime_address_ptr_ref(o)
+        assert cppyy.addressof(o) == pp.gime_address_ptr(o)
+        assert cppyy.addressof(o) == pp.gime_address_ptr_ptr(o)
+        assert cppyy.addressof(o) == pp.gime_address_ptr_ref(o)
 
         import array
-        addressofo = array.array('l', [_cppyy.addressof(o)])
-        assert addressofo.buffer_info()[0] == 
pp.gime_address_ptr_ptr(addressofo)
+        addressofo = array.array('l', [cppyy.addressof(o)])
+        assert addressofo[0] == pp.gime_address_ptr_ptr(addressofo)
 
         assert 0 == pp.gime_address_ptr(0)
-        assert 0 == pp.gime_address_ptr(None)
+        raises(TypeError, pp.gime_address_ptr, None)
 
-        ptr = _cppyy.bind_object(0, some_concrete_class)
-        assert _cppyy.addressof(ptr) == 0
+        ptr = cppyy.bind_object(0, some_concrete_class)
+        assert cppyy.addressof(ptr) == 0
         pp.set_address_ptr_ref(ptr)
-        assert _cppyy.addressof(ptr) == 0x1234
+        assert cppyy.addressof(ptr) == 0x1234
         pp.set_address_ptr_ptr(ptr)
-        assert _cppyy.addressof(ptr) == 0x4321
+        assert cppyy.addressof(ptr) == 0x4321
+
+        assert cppyy.addressof(cppyy.nullptr) == 0
+        raises(TypeError, cppyy.addressof, None)
+        assert cppyy.addressof(0)             == 0
 
     def test09_opaque_pointer_passing(self):
         """Test passing around of opaque pointers"""
 
-        import _cppyy
-        some_concrete_class = _cppyy.gbl.some_concrete_class
+        import _cppyy as cppyy
+        some_concrete_class = cppyy.gbl.some_concrete_class
 
         o = some_concrete_class()
 
         # TODO: figure out the PyPy equivalent of CObject (may have to do this
         # through the C-API from C++)
 
-        #cobj = _cppyy.as_cobject(o)
-        addr = _cppyy.addressof(o)
+        #cobj = cppyy.as_cobject(o)
+        addr = cppyy.addressof(o)
 
-        #assert o == _cppyy.bind_object(cobj, some_concrete_class)
-        #assert o == _cppyy.bind_object(cobj, type(o))
-        #assert o == _cppyy.bind_object(cobj, o.__class__)
-        #assert o == _cppyy.bind_object(cobj, "some_concrete_class")
-        assert _cppyy.addressof(o) == 
_cppyy.addressof(_cppyy.bind_object(addr, some_concrete_class))
-        assert o == _cppyy.bind_object(addr, some_concrete_class)
-        assert o == _cppyy.bind_object(addr, type(o))
-        assert o == _cppyy.bind_object(addr, o.__class__)
-        assert o == _cppyy.bind_object(addr, "some_concrete_class")
-        raises(TypeError, _cppyy.bind_object, addr, "does_not_exist")
-        raises(TypeError, _cppyy.bind_object, addr, 1)
+        #assert o == cppyy.bind_object(cobj, some_concrete_class)
+        #assert o == cppyy.bind_object(cobj, type(o))
+        #assert o == cppyy.bind_object(cobj, o.__class__)
+        #assert o == cppyy.bind_object(cobj, "some_concrete_class")
+        assert cppyy.addressof(o) == cppyy.addressof(cppyy.bind_object(addr, 
some_concrete_class))
+        assert o == cppyy.bind_object(addr, some_concrete_class)
+        assert o == cppyy.bind_object(addr, type(o))
+        assert o == cppyy.bind_object(addr, o.__class__)
+        assert o == cppyy.bind_object(addr, "some_concrete_class")
+        raises(TypeError, cppyy.bind_object, addr, "does_not_exist")
+        raises(TypeError, cppyy.bind_object, addr, 1)
 
     def test10_object_identity(self):
         """Test object identity"""
 
-        import _cppyy
-        some_concrete_class  = _cppyy.gbl.some_concrete_class
-        some_class_with_data = _cppyy.gbl.some_class_with_data
+        import _cppyy as cppyy
+        some_concrete_class  = cppyy.gbl.some_concrete_class
+        some_class_with_data = cppyy.gbl.some_class_with_data
 
         o = some_concrete_class()
-        addr = _cppyy.addressof(o)
+        addr = cppyy.addressof(o)
 
-        o2 = _cppyy.bind_object(addr, some_concrete_class)
+        o2 = cppyy.bind_object(addr, some_concrete_class)
         assert o is o2
 
-        o3 = _cppyy.bind_object(addr, some_class_with_data)
+        o3 = cppyy.bind_object(addr, some_class_with_data)
         assert not o is o3
 
         d1 = some_class_with_data()
@@ -472,13 +476,13 @@
     def test11_multi_methods(self):
         """Test calling of methods from multiple inheritance"""
 
-        import _cppyy
-        multi = _cppyy.gbl.multi
+        import _cppyy as cppyy
+        multi = cppyy.gbl.multi
 
-        assert _cppyy.gbl.multi1 is multi.__bases__[0]
-        assert _cppyy.gbl.multi2 is multi.__bases__[1]
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to