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

@ -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>;

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