Add support for friend templates, including operator overloading.

Closes #196.
This commit is contained in:
William S Fulton 2015-05-04 10:01:34 +01:00
commit 428b6176df
10 changed files with 146 additions and 3 deletions

View file

@ -5,6 +5,27 @@ See the RELEASENOTES file for a summary of changes in each release.
Version 3.0.6 (in progress) Version 3.0.6 (in progress)
=========================== ===========================
2015-05-04: wsfulton
Add support for friend templates, including operator overloading - fixes #196. Considering
the example below, previously the operator gave a syntax error and friendfunc incorrectly
warned with:
"Warning 503: Can't wrap 'friendfunc<(Type)>' unless renamed to a valid identifier."
template <class Type> class MyClass {
friend int friendfunc <Type>(double is, MyClass <Type> & x);
friend int operator<< <Type>(double un, const MyClass <Type> &x);
};
The following also previously incorrectly warned with:
"Warning 302: Identifier 'template_friend' redefined (ignored),"
template<typename T> T template_friend(T);
struct MyTemplate {
template<typename T> friend T template_friend(T);
};
2015-05-01: wsfulton 2015-05-01: wsfulton
Fix handling of conversion operators where the operator is split over multiple Fix handling of conversion operators where the operator is split over multiple
lines or has comments within the operator type. Fixes #401. lines or has comments within the operator type. Fixes #401.

View file

@ -234,6 +234,7 @@ CPP_TEST_CASES += \
features \ features \
fragments \ fragments \
friends \ friends \
friends_template \
funcptr_cpp \ funcptr_cpp \
fvirtual \ fvirtual \
global_namespace \ global_namespace \

View file

@ -0,0 +1,26 @@
%module cpp_template_friend
template<typename T> T template_friend1(T);
template<typename T> T template_friend1(T);
struct MyTemplate1 {
template<typename T> friend T template_friend1(T);
};
template<typename T> T template_friend2(T);
struct MyTemplate2 {
template<typename T> friend T template_friend2(T);
};
template<typename T> T template_friend2(T);
int normal_friend1(int);
int normal_friend1(int);
struct MyClass1 {
friend int normal_friend1(int);
};
int normal_friend2(int);
struct MyClass2 {
friend int normal_friend2(int);
};
int normal_friend2(int);

View file

@ -0,0 +1,8 @@
cpp_template_friend.i:4: Warning 302: Identifier 'template_friend1' redefined (ignored),
cpp_template_friend.i:3: Warning 302: previous definition of 'template_friend1'.
cpp_template_friend.i:13: Warning 302: Identifier 'template_friend2' redefined (ignored),
cpp_template_friend.i:9: Warning 302: previous definition of 'template_friend2'.
cpp_template_friend.i:17: Warning 322: Redundant redeclaration of 'normal_friend1',
cpp_template_friend.i:16: Warning 322: previous declaration of 'normal_friend1'.
cpp_template_friend.i:26: Warning 322: Redundant redeclaration of 'normal_friend2',
cpp_template_friend.i:22: Warning 322: previous declaration of 'normal_friend2'.

View file

@ -0,0 +1,46 @@
%module friends_template
%{
template <typename Type> class MyClass;
template <typename Type> int operator<<(double un, const MyClass <Type> & x) { return 0; }
template <typename Type> int funk_hidden(double is, MyClass <Type> & x) { return 2; }
template <typename T> T template_friend_hidden(T t) { return t + 1; }
%}
%inline %{
template <typename Type> int operator>>(double is, MyClass <Type> & x) { return 1; }
template <typename Type> int funk_seen(double is, MyClass <Type> & x) { return 2; }
template <typename T> T template_friend_seen(T t1, T t2) { return t1 + t2; }
int friend_plain_seen(int i) { return i; }
template <class Type> class MyClass
{
friend int operator<< <Type>(double un, const MyClass <Type> & x);
friend int operator>> <Type>(double is, MyClass <Type> & x);
friend int funk_hidden <Type>(double is, MyClass <Type> & x);
friend int funk_seen <Type>(double is, MyClass <Type> & x);
};
struct MyTemplate {
template <typename T> friend T template_friend_hidden(T);
template <typename T> friend T template_friend_seen(T, T);
friend int friend_plain_seen(int i);
};
MyClass<int> makeMyClassInt() { return MyClass<int>(); }
%}
// Although the friends in MyClass are automatically instantiated via %template(MyClassDouble) MyClass<int>,
// the operator friends are not valid and hence %rename is needed.
%rename(OperatorInputDouble) operator>> <double>;
%rename(OperatorOutputDouble) operator<< <double>;
%template(MyClassDouble) MyClass<double>;
%template(TemplateFriendHiddenInt) template_friend_hidden<int>;
%template(TemplateFriendSeenInt) template_friend_seen<int>;
// These have no %template(XX) MyClass<int> to instantiate, but they can be instantiated separately...
%template(OperatorInputInt) operator>> <int>;
%template(OperatorFunkSeenInt) funk_seen <int>;

View file

@ -0,0 +1,28 @@
import friends_template.*;
public class friends_template_runme {
static {
try {
System.loadLibrary("friends_template");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
System.exit(1);
}
}
public static void main(String argv[]) {
friends_template.OperatorOutputDouble(1.1, new MyClassDouble());
friends_template.OperatorInputDouble(1.1, new MyClassDouble());
friends_template.funk_hidden(1.1, new MyClassDouble());
friends_template.funk_seen(1.1, new MyClassDouble());
friends_template.TemplateFriendHiddenInt(0);
friends_template.TemplateFriendSeenInt(0, 0);
SWIGTYPE_p_MyClassT_int_t myClassInt = friends_template.makeMyClassInt();
friends_template.OperatorInputInt(1, myClassInt);
friends_template.OperatorFunkSeenInt(1.1, myClassInt);
}
}

View file

@ -6453,8 +6453,8 @@ idcolon : idtemplate idcolontail {
| NONID DCOLON idtemplate { | NONID DCOLON idtemplate {
$$ = NewStringf("::%s",$3); $$ = NewStringf("::%s",$3);
} }
| OPERATOR { | OPERATOR template_decl {
$$ = NewString($1); $$ = NewStringf("%s%s",$1,$2);
} }
| NONID DCOLON OPERATOR { | NONID DCOLON OPERATOR {
$$ = NewStringf("::%s",$3); $$ = NewStringf("::%s",$3);

View file

@ -97,6 +97,15 @@ static int cparse_template_expand(Node *n, String *tname, String *rname, String
Append(cpatchlist, Getattr(n, "sym:name")); Append(cpatchlist, Getattr(n, "sym:name"));
} }
} }
if (checkAttribute(n, "storage", "friend")) {
String *symname = Getattr(n, "sym:name");
if (symname) {
String *stripped_name = SwigType_templateprefix(symname);
Setattr(n, "sym:name", stripped_name);
Delete(stripped_name);
}
Append(typelist, Getattr(n, "name"));
}
add_parms(Getattr(n, "parms"), cpatchlist, typelist); add_parms(Getattr(n, "parms"), cpatchlist, typelist);
add_parms(Getattr(n, "throws"), cpatchlist, typelist); add_parms(Getattr(n, "throws"), cpatchlist, typelist);

View file

@ -940,7 +940,7 @@ int Language::cDeclaration(Node *n) {
} }
if (!validIdentifier(symname)) { if (!validIdentifier(symname)) {
Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap '%s' unless renamed to a valid identifier.\n", symname); Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap '%s' unless renamed to a valid identifier.\n", SwigType_namestr(symname));
return SWIG_NOWRAP; return SWIG_NOWRAP;
} }

View file

@ -1003,6 +1003,10 @@ static int nodes_are_equivalent(Node *a, Node *b, int a_inclass) {
} }
return 0; return 0;
} }
if (Equal(ta, "template") && Equal(tb, "template")) {
if (Cmp(a_storage, "friend") == 0 || Cmp(b_storage, "friend") == 0)
return 1;
}
} }
return 0; return 0;
} }