Add C++11 alias templates

This commit is contained in:
Lior Goldberg 2016-07-01 16:15:40 +03:00
commit d0fc5b7b5b
6 changed files with 128 additions and 55 deletions

View file

@ -622,20 +622,15 @@ which is equivalent to the old style typedef:
typedef void (*PFD)(double); // The old style typedef void (*PFD)(double); // The old style
</pre></div> </pre></div>
<p>
SWIG supports type aliasing.
</p>
<p> <p>
The following is an example of an alias template: The following is an example of an alias template:
<div class="code"><pre> <div class="code"><pre>
template&lt; typename T1, typename T2, int &gt; template&lt; typename T1, typename T2, int N &gt;
class SomeType { class SomeType {
public: public:
T1 a; T1 a;
T2 b; T2 b;
int c;
}; };
template&lt; typename T2 &gt; template&lt; typename T2 &gt;
@ -643,14 +638,14 @@ using TypedefName = SomeType&lt;char*, T2, 5&gt;;
</pre></div> </pre></div>
<p> <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> </p>
<div class="shell"> <div class="code"><pre>
<pre> %template(SomeTypeBool) SomeType&lt;char*, bool, 5&gt;;
example.i:13: Warning 342: The 'using' keyword in template aliasing is not fully supported yet. %template() TypedefName&lt;bool&gt;;
</pre> </pre></div>
</div>
<H3><a name="CPlusPlus11_unrestricted_unions">7.2.17 Unrestricted unions</a></H3> <H3><a name="CPlusPlus11_unrestricted_unions">7.2.17 Unrestricted unions</a></H3>

View file

@ -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 %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 %{ %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 { class SomeType {
public:
using type1_t = T1;
using type2_t = T2;
T1 a; T1 a;
T2 b; T2 b;
int c; constexpr int get_n() { return N; }
}; };
// template aliasing // Specialization for T1=const char*, T2=bool
template< typename T2 > template<int N>
using TypedefName = SomeType<char*, T2, 5>; class SomeType<const char*, bool, N> {
template< typename T2 > public:
using TypedefNamePtr = SomeType<char*, T2, 4>*; using type1_t = const char*;
using type2_t = bool;
// type aliasing type1_t a;
typedef void (*PFD)(double); // Old style type2_t b;
using PF = void (*)(double); // New introduced syntax constexpr int get_n() { return 3 * N; }
// use of template aliasing
template<typename Key,typename Val>
class MyCPP11Class {
}; };
template<typename VAL> using MyIntKeyClass = MyCPP11Class<int,VAL>;
MyIntKeyClass<char> intchar;
TypedefName<int> alias1(TypedefName<int> a) { return a; } // alias templates
TypedefNamePtr<int> alias1(TypedefNamePtr<int> a = nullptr) { return a; } 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; typedef double Val;
template<typename T> struct ListBucket { template<typename T> struct ListBucket {
}; };
namespace Alloc { namespace Alloc {
template<typename T> struct rebind { template<typename T> struct rebind {
typedef int other; using other = int;
}; };
} }
using BucketAllocator1 = typename Alloc::template rebind<ListBucket<Val>>::other; using BucketAllocator1 = typename Alloc::template rebind<ListBucket<Val>>::other;
using BucketAllocator2 = typename Alloc::template rebind<::template ListBucket<double>>::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>;

View file

@ -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")

View file

@ -2910,16 +2910,17 @@ c_declaration : c_decl {
add_symbols($$); add_symbols($$);
} }
| TEMPLATE LESSTHAN template_parms GREATERTHAN USING idcolon EQUAL type plain_declarator SEMI { | TEMPLATE LESSTHAN template_parms GREATERTHAN USING idcolon EQUAL type plain_declarator SEMI {
$$ = new_node("using"); /* Convert alias template to a "template" typedef statement */
Setattr($$,"name",$6); $$ = new_node("template");
SwigType_push($8,$9.type); 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($$); 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 */
} }
; ;

View file

@ -870,7 +870,7 @@ int Language::cDeclaration(Node *n) {
} else { } else {
// Found an unignored templated method that has an empty template instantiation (%template()) // Found an unignored templated method that has an empty template instantiation (%template())
// Ignore it unless it has been %rename'd // 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"); SetFlag(n, "feature:ignore");
Swig_warning(WARN_LANG_TEMPLATE_METHOD_IGNORE, input_file, line_number, Swig_warning(WARN_LANG_TEMPLATE_METHOD_IGNORE, input_file, line_number,
"%%template() contains no name. Template method ignored: %s\n", Swig_name_decl(n)); "%%template() contains no name. Template method ignored: %s\n", Swig_name_decl(n));

View file

@ -566,6 +566,10 @@ class TypePass:private Dispatcher {
SwigType_typedef_class(rname); SwigType_typedef_class(rname);
Delete(rname); Delete(rname);
/* SwigType_typedef_class(name); */ /* 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; return SWIG_OK;
} }