mirror of https://github.com/swig/swig
Add support for friend templates, including operator overloading.
Closes #196.
This commit is contained in:
parent
e044dc4405
commit
428b6176df
|
@ -5,6 +5,27 @@ See the RELEASENOTES file for a summary of changes in each release.
|
|||
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
|
||||
Fix handling of conversion operators where the operator is split over multiple
|
||||
lines or has comments within the operator type. Fixes #401.
|
||||
|
|
|
@ -234,6 +234,7 @@ CPP_TEST_CASES += \
|
|||
features \
|
||||
fragments \
|
||||
friends \
|
||||
friends_template \
|
||||
funcptr_cpp \
|
||||
fvirtual \
|
||||
global_namespace \
|
||||
|
|
|
@ -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);
|
|
@ -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'.
|
|
@ -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>;
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -6453,8 +6453,8 @@ idcolon : idtemplate idcolontail {
|
|||
| NONID DCOLON idtemplate {
|
||||
$$ = NewStringf("::%s",$3);
|
||||
}
|
||||
| OPERATOR {
|
||||
$$ = NewString($1);
|
||||
| OPERATOR template_decl {
|
||||
$$ = NewStringf("%s%s",$1,$2);
|
||||
}
|
||||
| NONID DCOLON OPERATOR {
|
||||
$$ = NewStringf("::%s",$3);
|
||||
|
|
|
@ -97,6 +97,15 @@ static int cparse_template_expand(Node *n, String *tname, String *rname, String
|
|||
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, "throws"), cpatchlist, typelist);
|
||||
|
|
|
@ -940,7 +940,7 @@ int Language::cDeclaration(Node *n) {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1003,6 +1003,10 @@ static int nodes_are_equivalent(Node *a, Node *b, int a_inclass) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
if (Equal(ta, "template") && Equal(tb, "template")) {
|
||||
if (Cmp(a_storage, "friend") == 0 || Cmp(b_storage, "friend") == 0)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue