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