swig/Examples/test-suite/cpp17_using_pack_expansion.i

97 lines
3.9 KiB
OpenEdge ABL

%module cpp17_using_pack_expansion
// C++17 added pack expansion in a using-declaration ('using Ts::name...;') - P0195. Its typical
// usage is the 'Overloaded' helper combined with std::visit on a std::variant:
//
// template <typename... Ts> struct Overloaded : Ts... { using Ts::operator()...; };
//
// The using-declaration pulls each base's operator() into Overloaded's overload set, so calling
// an Overloaded instance dispatches by argument type to the matching base. This testcase
// exercises that grammar with ordinary functor structs as the operator() bases (pure C++17);
// visit_functors_int() and visit_functors_double() show the typical c++ std::visit idiom.
%include <std_string.i>
// SWIGWARN_LANG_OVERLOAD_SHADOW: lua only has one numeric type, so the int/double overloads of
// operator() shadow each other. The other warnings suppress per target multiple inheritance notes.
%warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE,
SWIGWARN_CSHARP_MULTIPLE_INHERITANCE,
SWIGWARN_D_MULTIPLE_INHERITANCE,
SWIGWARN_PHP_MULTIPLE_INHERITANCE,
SWIGWARN_RUBY_MULTIPLE_INHERITANCE,
SWIGWARN_LANG_OVERLOAD_SHADOW) Overloaded<IntCase, DoubleCase>;
%warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE,
SWIGWARN_CSHARP_MULTIPLE_INHERITANCE,
SWIGWARN_D_MULTIPLE_INHERITANCE,
SWIGWARN_PHP_MULTIPLE_INHERITANCE,
SWIGWARN_RUBY_MULTIPLE_INHERITANCE,
SWIGWARN_LANG_OVERLOAD_SHADOW) Mixed<int, double>;
#ifdef SWIGD
// D supports single inheritance only. Without these ignores the using-declaration brings the
// second base's operator()(double) into the D proxy with an 'override' keyword that has no
// matching base method, a D compile error.
%ignore DoubleCase::operator();
%ignore Base<double>::operator();
#endif
%rename(call) *::operator();
%inline %{
#include <string>
#include <variant>
struct IntCase { std::string operator()(int v) const { return "Int:" + std::to_string(v); } };
struct DoubleCase { std::string operator()(double v) const { return "Double:" + std::to_string(v); } };
template <typename... Ts>
struct Overloaded : Ts... {
using Ts::operator()...;
};
template <typename T>
struct Base {
std::string operator()(T v) const { return "T:" + std::to_string(v); }
};
// 'Mixed<Ts...>' uses a nested qualifier inside the using-declaration
// ('using Base<Ts>::operator()...;'), so the pack name expands inside the template-id of the base
// rather than as the leading scope.
template <typename... Ts>
struct Mixed : Base<Ts>... {
using Base<Ts>::operator()...;
};
// Member methods either side of the pack using-declaration. When the pack is empty the
// using-declaration is removed and the surrounding member methods must remain in the
// instantiated class with their sibling chain intact.
template <typename... Ts>
struct WithMembers : Ts... {
std::string before_using() const { return "before"; }
using Ts::operator()...;
std::string after_using() const { return "after"; }
};
inline std::string visit_functors_int(int x) {
std::variant<int,double> v{x};
return std::visit(Overloaded<IntCase,DoubleCase>{}, v);
}
inline std::string visit_functors_double(double x) {
std::variant<int,double> v{x};
return std::visit(Overloaded<IntCase,DoubleCase>{}, v);
}
%}
%template(OverloadedIntDouble) Overloaded<IntCase,DoubleCase>;
%template(BaseInt) Base<int>;
%template(BaseDouble) Base<double>;
%template(MixedIntDouble) Mixed<int, double>;
// Empty pack: the using-declaration introduces no names, so the instantiated class has no
// inherited operator() and the proxy class is constructible but exposes no call methods.
// WithMembersEmpty additionally checks that the surrounding member methods survive intact
// when the using-decl is removed from between them.
%template(OverloadedEmpty) Overloaded<>;
%template(MixedEmpty) Mixed<>;
%template(WithMembersEmpty) WithMembers<>;