mirror of https://github.com/swig/swig
Add C++11 alias templates
This commit is contained in:
parent
36bbeb478d
commit
d0fc5b7b5b
|
@ -622,20 +622,15 @@ which is equivalent to the old style typedef:
|
|||
typedef void (*PFD)(double); // The old style
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
SWIG supports type aliasing.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The following is an example of an alias template:
|
||||
|
||||
<div class="code"><pre>
|
||||
template< typename T1, typename T2, int >
|
||||
template< typename T1, typename T2, int N >
|
||||
class SomeType {
|
||||
public:
|
||||
T1 a;
|
||||
T2 b;
|
||||
int c;
|
||||
};
|
||||
|
||||
template< typename T2 >
|
||||
|
@ -643,14 +638,14 @@ using TypedefName = SomeType<char*, T2, 5>;
|
|||
</pre></div>
|
||||
|
||||
<p>
|
||||
These are partially supported as SWIG will parse these and identify them, however, they are ignored as they are not added to the type system. A warning such as the following is issued:
|
||||
SWIG supports both type aliasing and alias templates.
|
||||
However, in order to use an alias template, the <tt>%template</tt> directive must be used:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
example.i:13: Warning 342: The 'using' keyword in template aliasing is not fully supported yet.
|
||||
</pre>
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
%template(SomeTypeBool) SomeType<char*, bool, 5>;
|
||||
%template() TypedefName<bool>;
|
||||
</pre></div>
|
||||
|
||||
<H3><a name="CPlusPlus11_unrestricted_unions">7.2.17 Unrestricted unions</a></H3>
|
||||
|
||||
|
|
|
@ -1,56 +1,86 @@
|
|||
/* This testcase checks whether SWIG correctly parses alias templates. */
|
||||
/* This testcase checks whether SWIG correctly handles alias templates. */
|
||||
%module cpp11_template_typedefs
|
||||
|
||||
%warnfilter(SWIGWARN_CPP11_ALIAS_TEMPLATE) TypedefName;
|
||||
%warnfilter(SWIGWARN_CPP11_ALIAS_TEMPLATE) TypedefNamePtr;
|
||||
%warnfilter(SWIGWARN_CPP11_ALIAS_TEMPLATE) MyIntKeyClass;
|
||||
%warnfilter(SWIGWARN_CPP11_ALIAS_DECLARATION) PF;
|
||||
%warnfilter(SWIGWARN_CPP11_ALIAS_DECLARATION) BucketAllocator1;
|
||||
%warnfilter(SWIGWARN_CPP11_ALIAS_DECLARATION) BucketAllocator2;
|
||||
|
||||
// This warning should go away when type aliasing is supported
|
||||
#pragma SWIG nowarn=SWIGWARN_PARSE_USING_UNDEF // Nothing known about 'p.SomeType< char *,T2,4 >'.
|
||||
|
||||
%inline %{
|
||||
template< typename T1, typename T2, int >
|
||||
|
||||
template<typename T>
|
||||
using ptr_t = T*;
|
||||
|
||||
namespace ns {
|
||||
|
||||
template<typename T1, typename T2, int N>
|
||||
class SomeType {
|
||||
public:
|
||||
using type1_t = T1;
|
||||
using type2_t = T2;
|
||||
T1 a;
|
||||
T2 b;
|
||||
int c;
|
||||
constexpr int get_n() { return N; }
|
||||
};
|
||||
|
||||
// template aliasing
|
||||
template< typename T2 >
|
||||
using TypedefName = SomeType<char*, T2, 5>;
|
||||
template< typename T2 >
|
||||
using TypedefNamePtr = SomeType<char*, T2, 4>*;
|
||||
|
||||
// type aliasing
|
||||
typedef void (*PFD)(double); // Old style
|
||||
using PF = void (*)(double); // New introduced syntax
|
||||
|
||||
|
||||
// use of template aliasing
|
||||
template<typename Key,typename Val>
|
||||
class MyCPP11Class {
|
||||
// Specialization for T1=const char*, T2=bool
|
||||
template<int N>
|
||||
class SomeType<const char*, bool, N> {
|
||||
public:
|
||||
using type1_t = const char*;
|
||||
using type2_t = bool;
|
||||
type1_t a;
|
||||
type2_t b;
|
||||
constexpr int get_n() { return 3 * N; }
|
||||
};
|
||||
template<typename VAL> using MyIntKeyClass = MyCPP11Class<int,VAL>;
|
||||
MyIntKeyClass<char> intchar;
|
||||
|
||||
TypedefName<int> alias1(TypedefName<int> a) { return a; }
|
||||
TypedefNamePtr<int> alias1(TypedefNamePtr<int> a = nullptr) { return a; }
|
||||
%}
|
||||
// alias templates
|
||||
template<typename T2>
|
||||
using TypedefName = SomeType<const char*, T2, 5>;
|
||||
template<typename T2>
|
||||
using TypedefNamePtr = ptr_t<SomeType<const char*, T2, 4>>;
|
||||
|
||||
// alias template that returns T2 for a SomeType<T1,T2,N> class
|
||||
template<typename T>
|
||||
using T2_of = typename T::type2_t;
|
||||
|
||||
T2_of<TypedefName<int>> get_SomeType_b(const SomeType<const char*, int, 5>& x) { return x.b; }
|
||||
|
||||
template<typename T>
|
||||
T2_of<TypedefName<T>> get_SomeType_b2(const TypedefName<T>& x) { return x.b; }
|
||||
|
||||
} // namespace ns
|
||||
|
||||
ns::TypedefName<int> create_TypedefName() { return { "hello", 10}; }
|
||||
ns::TypedefName<bool> create_TypedefNameBool() { return { "hello", true}; }
|
||||
ns::TypedefNamePtr<int> identity(ns::TypedefNamePtr<int> a = nullptr) { return a; }
|
||||
|
||||
%inline %{
|
||||
typedef double Val;
|
||||
template<typename T> struct ListBucket {
|
||||
};
|
||||
namespace Alloc {
|
||||
template<typename T> struct rebind {
|
||||
typedef int other;
|
||||
using other = int;
|
||||
};
|
||||
}
|
||||
|
||||
using BucketAllocator1 = typename Alloc::template rebind<ListBucket<Val>>::other;
|
||||
using BucketAllocator2 = typename Alloc::template rebind<::template ListBucket<double>>::other;
|
||||
|
||||
BucketAllocator1 get_bucket_allocator1() { return 1; }
|
||||
BucketAllocator2 get_bucket_allocator2() { return 2; }
|
||||
%}
|
||||
|
||||
%immutable ns::SomeType::a;
|
||||
|
||||
// %template() directives
|
||||
|
||||
%template(SomeTypeInt5) ns::SomeType<const char*, int, 5>;
|
||||
%template(SomeTypeInt4) ns::SomeType<const char*, int, 4>;
|
||||
%template(SomeTypeBool5) ns::SomeType<const char*, bool, 5>;
|
||||
|
||||
%template(ListBucketDouble) ListBucket<Val>;
|
||||
%template(RebindListBucketDouble) Alloc::rebind<ListBucket<Val>>;
|
||||
|
||||
%template() ptr_t<ns::SomeType<const char*, int, 4>>;
|
||||
%template() ns::TypedefName<int>;
|
||||
%template() ns::TypedefName<bool>;
|
||||
%template() ns::TypedefNamePtr<int>;
|
||||
%template() ns::T2_of<ns::TypedefName<int>>;
|
||||
|
||||
%template(get_SomeType_b2) ns::get_SomeType_b2<int>;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
from cpp11_template_typedefs import *
|
||||
|
||||
t = create_TypedefName()
|
||||
if type(t).__name__ != "SomeTypeInt5":
|
||||
raise RuntimeError("type(t) is '%s' and should be 'SomeTypeInt5'" % type(t).__name__)
|
||||
|
||||
if t.a != "hello":
|
||||
raise RuntimeError("t.a should be 'hello'")
|
||||
if t.b != 10:
|
||||
raise RuntimeError("t.b should be 10")
|
||||
if t.get_n() != 5:
|
||||
raise RuntimeError("t.get_n() should be 5")
|
||||
|
||||
t_bool = create_TypedefNameBool()
|
||||
if type(t_bool).__name__ != "SomeTypeBool5":
|
||||
raise RuntimeError("type(t_bool) is '%s' and should be 'SomeTypeBool5'" % type(t_bool).__name__)
|
||||
|
||||
if t_bool.a != "hello":
|
||||
raise RuntimeError("t_bool.a should be 'hello'")
|
||||
if t_bool.b != True:
|
||||
raise RuntimeError("t_bool.b should be True")
|
||||
if t_bool.get_n() != 15:
|
||||
raise RuntimeError("t_bool.get_n() should be 15")
|
||||
|
||||
if get_SomeType_b(t) != 10:
|
||||
raise RuntimeError("get_SomeType_b(t) should be 10")
|
||||
|
||||
if get_SomeType_b2(t) != 10:
|
||||
raise RuntimeError("get_SomeType_b2(t) should be 10")
|
||||
|
||||
t2 = SomeTypeInt4()
|
||||
t2.b = 0
|
||||
t3 = identity(t2)
|
||||
t3.b = 5
|
||||
if t2.b != 5:
|
||||
raise RuntimeError("t2.b should be 5")
|
||||
|
||||
if get_bucket_allocator1() != 1:
|
||||
raise RuntimeError("bucket_allocator1 should be 1")
|
||||
|
||||
# SWIG doesn't handle ::MyClass as a template argument. Skip this test.
|
||||
#if get_bucket_allocator2() != 2:
|
||||
# raise RuntimeError("bucket_allocator2 should be 2")
|
|
@ -2910,16 +2910,17 @@ c_declaration : c_decl {
|
|||
add_symbols($$);
|
||||
}
|
||||
| TEMPLATE LESSTHAN template_parms GREATERTHAN USING idcolon EQUAL type plain_declarator SEMI {
|
||||
$$ = new_node("using");
|
||||
Setattr($$,"name",$6);
|
||||
/* Convert alias template to a "template" typedef statement */
|
||||
$$ = new_node("template");
|
||||
SwigType_push($8,$9.type);
|
||||
Setattr($$,"uname",$8);
|
||||
Setattr($$,"type",$8);
|
||||
Setattr($$,"storage","typedef");
|
||||
Setattr($$,"name",$6);
|
||||
Setattr($$,"decl","");
|
||||
Setattr($$,"templateparms",$3);
|
||||
Setattr($$,"templatetype","cdecl");
|
||||
SetFlag($$,"aliastemplate");
|
||||
add_symbols($$);
|
||||
SWIG_WARN_NODE_BEGIN($$);
|
||||
Swig_warning(WARN_CPP11_ALIAS_TEMPLATE, cparse_file, cparse_line, "The 'using' keyword in template aliasing is not fully supported yet.\n");
|
||||
SWIG_WARN_NODE_END($$);
|
||||
|
||||
$$ = 0; /* TODO - ignored for now */
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
@ -870,7 +870,7 @@ int Language::cDeclaration(Node *n) {
|
|||
} else {
|
||||
// Found an unignored templated method that has an empty template instantiation (%template())
|
||||
// Ignore it unless it has been %rename'd
|
||||
if (Strncmp(symname, "__dummy_", 8) == 0) {
|
||||
if (Strncmp(symname, "__dummy_", 8) == 0 && Cmp(storage, "typedef") != 0) {
|
||||
SetFlag(n, "feature:ignore");
|
||||
Swig_warning(WARN_LANG_TEMPLATE_METHOD_IGNORE, input_file, line_number,
|
||||
"%%template() contains no name. Template method ignored: %s\n", Swig_name_decl(n));
|
||||
|
|
|
@ -566,6 +566,10 @@ class TypePass:private Dispatcher {
|
|||
SwigType_typedef_class(rname);
|
||||
Delete(rname);
|
||||
/* SwigType_typedef_class(name); */
|
||||
} else if (Strcmp(ttype, "cdecl") == 0) {
|
||||
String *rname = SwigType_typedef_resolve_all(name);
|
||||
SwigType_typedef_class(rname);
|
||||
Delete(rname);
|
||||
}
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue