diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html
index a4845832e..2f3783327 100644
--- a/Doc/Manual/CPlusPlus11.html
+++ b/Doc/Manual/CPlusPlus11.html
@@ -622,20 +622,15 @@ which is equivalent to the old style typedef:
typedef void (*PFD)(double); // The old style
-
-SWIG supports type aliasing.
-
-
The following is an example of an alias template:
-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>;
-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 %template directive must be used:
-
-
-example.i:13: Warning 342: The 'using' keyword in template aliasing is not fully supported yet.
-
-
+
+%template(SomeTypeBool) SomeType<char*, bool, 5>;
+%template() TypedefName<bool>;
+
diff --git a/Examples/test-suite/cpp11_template_typedefs.i b/Examples/test-suite/cpp11_template_typedefs.i
index 97a1da7ed..02cb8ac30 100644
--- a/Examples/test-suite/cpp11_template_typedefs.i
+++ b/Examples/test-suite/cpp11_template_typedefs.i
@@ -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
+using ptr_t = T*;
+
+namespace ns {
+
+template
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;
-template< typename T2 >
-using TypedefNamePtr = SomeType*;
-
-// type aliasing
-typedef void (*PFD)(double); // Old style
-using PF = void (*)(double); // New introduced syntax
-
-
-// use of template aliasing
-template
-class MyCPP11Class {
+// Specialization for T1=const char*, T2=bool
+template
+class SomeType {
+public:
+ using type1_t = const char*;
+ using type2_t = bool;
+ type1_t a;
+ type2_t b;
+ constexpr int get_n() { return 3 * N; }
};
-template using MyIntKeyClass = MyCPP11Class;
-MyIntKeyClass intchar;
-TypedefName alias1(TypedefName a) { return a; }
-TypedefNamePtr alias1(TypedefNamePtr a = nullptr) { return a; }
-%}
+// alias templates
+template
+using TypedefName = SomeType;
+template
+using TypedefNamePtr = ptr_t>;
+
+// alias template that returns T2 for a SomeType class
+template
+using T2_of = typename T::type2_t;
+
+T2_of> get_SomeType_b(const SomeType& x) { return x.b; }
+
+template
+T2_of> get_SomeType_b2(const TypedefName& x) { return x.b; }
+
+} // namespace ns
+
+ns::TypedefName create_TypedefName() { return { "hello", 10}; }
+ns::TypedefName create_TypedefNameBool() { return { "hello", true}; }
+ns::TypedefNamePtr identity(ns::TypedefNamePtr a = nullptr) { return a; }
-%inline %{
typedef double Val;
template struct ListBucket {
};
namespace Alloc {
template struct rebind {
- typedef int other;
+ using other = int;
};
}
using BucketAllocator1 = typename Alloc::template rebind>::other;
using BucketAllocator2 = typename Alloc::template rebind<::template ListBucket>::other;
+
+BucketAllocator1 get_bucket_allocator1() { return 1; }
+BucketAllocator2 get_bucket_allocator2() { return 2; }
%}
+
+%immutable ns::SomeType::a;
+
+// %template() directives
+
+%template(SomeTypeInt5) ns::SomeType;
+%template(SomeTypeInt4) ns::SomeType;
+%template(SomeTypeBool5) ns::SomeType;
+
+%template(ListBucketDouble) ListBucket;
+%template(RebindListBucketDouble) Alloc::rebind>;
+
+%template() ptr_t>;
+%template() ns::TypedefName;
+%template() ns::TypedefName;
+%template() ns::TypedefNamePtr;
+%template() ns::T2_of>;
+
+%template(get_SomeType_b2) ns::get_SomeType_b2;
diff --git a/Examples/test-suite/python/cpp11_template_typedefs_runme.py b/Examples/test-suite/python/cpp11_template_typedefs_runme.py
new file mode 100644
index 000000000..4d6fc2629
--- /dev/null
+++ b/Examples/test-suite/python/cpp11_template_typedefs_runme.py
@@ -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")
diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
index 784187c28..4b06d3bd3 100644
--- a/Source/CParse/parser.y
+++ b/Source/CParse/parser.y
@@ -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 */
}
;
diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx
index 9b1173443..57b0d50e6 100644
--- a/Source/Modules/lang.cxx
+++ b/Source/Modules/lang.cxx
@@ -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));
diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx
index dc4d02bdd..bf8028c29 100644
--- a/Source/Modules/typepass.cxx
+++ b/Source/Modules/typepass.cxx
@@ -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;
}