Challenge: adding new method overloads when existing consumers use {} with args
Friedrich W. H. Kossebau
kossebau at kde.org
Wed Jul 27 12:51:48 BST 2022
Am Montag, 25. Juli 2022, 15:21:43 CEST schrieb Arjen Hiemstra:
> On Monday, 25 July 2022 14:22:45 CEST Friedrich W. H. Kossebau wrote:
> > Am Montag, 25. Juli 2022, 10:19:39 CEST schrieb David Redondo:
> > > Am Samstag, 23. Juli 2022, 17:20:08 CEST schrieb Friedrich W. H.
> > > Kossebau:
> > > Adding such an overload as in your example is source incompatible
> > > regardless. See also our guidelines.
> > > https://community.kde.org/Policies/
> > > Binary_Compatibility_Issues_With_C%2B%2B#Note_about_ABI
> > >
> > > You cannot...
> > >
> > > For existing functions of any type:
> > > Add an overload (binary compatible, but not source compatible: it
> > > makes
> > >
> > > &func ambiguous). Adding overloads to already overloaded functions is ok
> > > (since any use of &func already needed a cast).
> >
> > Indeed, this also was not on the radar of all those adding the overloads
> > to
> > KMessageBox recently, will discuss elsewhere.
> >
> > But let's try to improve the example then, as the new challenge by {}
> > still
> > exists:
> >
> > Given a class C with methods fpo() and foo(A a):
> > --- 8< ---
> >
> > class C
> > {
> >
> > public:
> > void foo();
> > void foo(A a);
> >
> > };
> >
> > --- 8< ---
> >
> > Now you want to add an overload, to serve further use-cases as requested
> > by
> > API consumers:
> > --- 8< ---
> >
> > void foo(B b);
> >
> > --- 8< ---
> >
> >
> > But there is existing consumer code, making use of C++17, which calls
> > --- 8< ---
> >
> > C c;
> > c.foo({});
> >
> > --- 8< ---
> >
> > So the new overload will not be source-compatible and break existing code.
> >
> > What to do about {} being a API addition roadblocker here in C++17 worlds?
>
> You could try using SFINAE:
>
> ```
> struct Test {
> void foo() { }
> void foo(const std::vector<int>& t) { }
>
> template <typename T>
> void foo(const T& t, std::enable_if_t<std::is_same<T,
> std::map<int,int>>::value, bool> = false)
> {
> }
> };
>
> Test t;
> t.foo({});
> ```
>
> In this case, the second overload will not be considered for `{}` as its
> type will be deduced as `std::initializer_list` and will not be the same as
> `std::map<int, int>`.
Thanks, interesting idea.
Drawbacks I see:
* new overload method (and any further ones) will stay special
* unless implementation is fine to do as part of template,
needs another method
* existing consumer code using {} is not that simple to map by human readers
as to which overload will be used
This inspires another idea though (still need to investigate if that works):
there could be another template overload added which catches any
`std::initializer_list` arg and delegating to the old method, thus removing
the ambiguity and also allowing to emit a compiler warning for this usage?
Cheers
Friedrich
More information about the kde-devel
mailing list