Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #68143 > unrolled thread
| Started by | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| First post | 2019-09-02 21:41 -0400 |
| Last post | 2019-09-18 08:22 -0700 |
| Articles | 10 — 5 participants |
Back to article view | Back to comp.lang.c++
forward variable number of arguments precisely to a template method Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-02 21:41 -0400
Re: forward variable number of arguments precisely to a template method Öö Tiib <ootiib@hot.ee> - 2019-09-03 00:24 -0700
Re: forward variable number of arguments precisely to a template method Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-04 10:47 -0400
Re: forward variable number of arguments precisely to a template method Manfred <noname@add.invalid> - 2019-09-05 20:21 +0200
Re: forward variable number of arguments precisely to a template method Vir Campestris <vir.campestris@invalid.invalid> - 2019-09-03 21:29 +0100
Re: forward variable number of arguments precisely to a template method Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-04 11:08 -0400
Re: forward variable number of arguments precisely to a template method Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-09-06 03:17 -0700
Re: forward variable number of arguments precisely to a template method Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-06 23:48 -0400
Problem solved: forward variable number of arguments precisely to a template method Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-07 10:16 -0400
Re: Problem solved: forward variable number of arguments precisely to a template method Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-09-18 08:22 -0700
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-02 21:41 -0400 |
| Subject | forward variable number of arguments precisely to a template method |
| Message-ID | <pxjbF.468705$tG2.346514@fx48.iad> |
Trying to write generic code for forwarding arguments via a template
method to methods defined in an interface precisely (in particular, all
references should be forwarded as references and values as values).
Using gcc 4.8.5 and -std=c++11 (cannot change). The best code I could
come up with so far is below.
Taking the below code as an example, I want generated `callMethod' to
have exactly same last 2 parameter types as the interface method it
calls ((I,I) for ma, (const I&, const I&) for mb and (const I&, I) for
mc). The below code generates, according to nm output,
void Caller<IA, 1>::callMethod<void (IA::*)(I, I), I const&, I
const&>(void (IA::*)(I, I), I const&, I const&)
void Caller<IA, 2>::callMethod<void (IA::*)(I const&, I const&), I&,
I&>(void (IA::*)(I const&, I const&), I&, I&)
void Caller<IA, 3>::callMethod<void (IA::*)(I const&, I), I const&, I
const&>(void (IA::*)(I const&, I), I const&, I const&)
commented implementations of callMethod are also failed tries (the last
one passes all Is to callMethod by value, the first two do not compile
at least one of the instantiations).
Any ideas? (gcc 4.8.5 / -std=c++11 is of utmost interest but any working
configuration would help)
TIA,
-Pavel
-----------
#include <iostream>
#include <functional>
using namespace std;
struct I;
ostream& operator<<(ostream&, const I&);
struct I {
int i_;
I(int i): i_(i) {}
I(const I& i): i_(i.i_) {
cout << "I(c&" << i << ")\n";
}
I(I&& i): i_(i.i_) {
cout << "I(&&" << i << ")\n";
}
};
ostream&
operator<<(ostream& os, const I& i) { return os << i.i_; }
struct IA {
virtual void ma(I, I) = 0;
virtual void mb(const I&, const I&) = 0;
virtual void mc(const I&, I) = 0;
};
template <class T, const int> // second parameter is to
// distinguish the prototypesin nm output with certainty
struct Caller {
Caller(T& to): o(to) {}
T& o;
/*
template<class... A>
void callMethod(void (T::*m)(A...), A&&... args) {
(o.*m)(forward<A>(args)...);
}
template<class... A>
void callMethod(void (T::*m)(A...), A... args) {
(o.*m)(args...);
}
template<class M, class... A>
void callMethod(M m, A... args) {
(o.*m)(args...);
}
*/
template<class M, class... A>
void callMethod(M m, A&&... args) {
(o.*m)(forward<A>(args)...);
}
};
struct A: public IA {
void ma(I, I) override
{ cout << "A::ma(I, I)\n"; }
void mb(const I&, const I&) override
{ cout << "A::mb(const I& , const I&)\n"; }
void mc(const I&, I) override
{ cout << "A::mc(const I& , I)\n"; }
};
int
main(int, char*[])
{
A a;
const I i1{1};
const I i2{2};
I i3{3};
I i4{4};
const I i5{5};
const I i6{6};
Caller<IA, 1>(a).callMethod(&IA::ma, i1, i2);
Caller<IA, 2>(a).callMethod(&IA::mb, i3, i4);
Caller<IA, 3>(a).callMethod(&IA::mc, i5, i6);
return 0;
}
-----------
[toc] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-09-03 00:24 -0700 |
| Message-ID | <e88fa91f-76c5-48fd-a22e-35b679f9b1a1@googlegroups.com> |
| In reply to | #68143 |
On Tuesday, 3 September 2019 04:41:51 UTC+3, Pavel wrote: > > Any ideas? (gcc 4.8.5 / -std=c++11 is of utmost interest but any working > configuration would help) What was the question or issue? Did read 3 times over but somehow missed it. :( Perhaps I need a coffee.
[toc] | [prev] | [next] | [standalone]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-04 10:47 -0400 |
| Message-ID | <d8QbF.368161$oq9.94140@fx47.iad> |
| In reply to | #68154 |
Öö Tiib wrote: > On Tuesday, 3 September 2019 04:41:51 UTC+3, Pavel wrote: >> >> Any ideas? (gcc 4.8.5 / -std=c++11 is of utmost interest but any working >> configuration would help) > > What was the question or issue? Did read 3 times over but somehow missed > it. :( Perhaps I need a coffee. > I want Caller<IA, 1>::callMethod to have prototype void Caller<IA, 1>::callMethod<void (IA::*)(I, I), I, I>(void (IA::*)(I, I), I, I) , Caller<IA, 2>::callMethod to have prototype void Caller<IA, 2>::callMethod<void (IA::*)(I const&, I const&), I const&, I const&>(void (IA::*)(I const&, I const&), I const&, I const&) and Caller<IA, 3>::callMethod to have prototype void Caller<IA, 3>::callMethod<void (IA::*)(I const&, I), I const&, I>(void (IA::*)(I const&, I), I const&, I) In other words, I want callMethod generated from the callMethod method template to take exactly same parameter types for its last 2 parameters as does the interface method to which the callMethod method forwards. I could not achieve this by any of callMethod template definitions I tried. E.g. the currently-uncommented in my example definition generates the methods with the prototypes shown in the original post (1st and 3rd of which are different from the above).
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2019-09-05 20:21 +0200 |
| Message-ID | <qkrjnp$1jd$2@gioia.aioe.org> |
| In reply to | #68217 |
On 9/4/2019 4:47 PM, Pavel wrote: > Öö Tiib wrote: >> On Tuesday, 3 September 2019 04:41:51 UTC+3, Pavel wrote: >>> >>> Any ideas? (gcc 4.8.5 / -std=c++11 is of utmost interest but any working >>> configuration would help) >> >> What was the question or issue? Did read 3 times over but somehow missed >> it. :( Perhaps I need a coffee. >> > I want Caller<IA, 1>::callMethod to have prototype > void Caller<IA, 1>::callMethod<void (IA::*)(I, I), I, I>(void (IA::*)(I, > I), I, I) > > , > > Caller<IA, 2>::callMethod to have prototype > void Caller<IA, 2>::callMethod<void (IA::*)(I const&, I const&), I const&, > I const&>(void (IA::*)(I const&, I const&), I const&, I const&) > > and > > Caller<IA, 3>::callMethod to have prototype > void Caller<IA, 3>::callMethod<void (IA::*)(I const&, I), I const&, > I>(void (IA::*)(I const&, I), I const&, I) > > In other words, I want callMethod generated from the callMethod method > template to take exactly same parameter types for its last 2 parameters > as does the interface method to which the callMethod method forwards. > > I could not achieve this by any of callMethod template definitions I > tried. E.g. the currently-uncommented in my example definition generates > the methods with the prototypes shown in the original post (1st and 3rd > of which are different from the above). > > > FWIW gcc 9.1.1 behaves the same way.
[toc] | [prev] | [next] | [standalone]
| From | Vir Campestris <vir.campestris@invalid.invalid> |
|---|---|
| Date | 2019-09-03 21:29 +0100 |
| Message-ID | <qkmif8$c92$4@dont-email.me> |
| In reply to | #68143 |
On 03/09/2019 02:41, Pavel wrote: > Any ideas? (gcc 4.8.5 / -std=c++11 is of utmost interest but any working > configuration would help) We're currently taking the pain of upgrading from GCC4.8. The pain of _not_ upgrading has become too much... you realise GCC 4.8 came out in 2013, and all you've had since then is bug fixes? And not all bugs get fixed? Andy
[toc] | [prev] | [next] | [standalone]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-04 11:08 -0400 |
| Message-ID | <rrQbF.220060$Zz1.33236@fx35.iad> |
| In reply to | #68183 |
Vir Campestris wrote: > On 03/09/2019 02:41, Pavel wrote: >> Any ideas? (gcc 4.8.5 / -std=c++11 is of utmost interest but any working >> configuration would help) > > We're currently taking the pain of upgrading from GCC4.8. The pain of > _not_ upgrading has become too much... you realise GCC 4.8 came out in > 2013, and all you've had since then is bug fixes? And not all bugs get > fixed? Yes. In this case I am the wrong tree to ... blame :-) for non-upgrading. Regardless, I have not yet got a solution for any compiler. If somebody threw at me a solution that worked on a later compiler but not gcc 4.8.5, it would be a good addition to my list of reasons for the upgrade. > > Andy
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2019-09-06 03:17 -0700 |
| Message-ID | <86imq5wwyj.fsf@mailhub.linuxsc.com> |
| In reply to | #68143 |
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
> Trying to write generic code for forwarding arguments via a
> template method to methods defined in an interface precisely (in
> particular, all references should be forwarded as references and
> values as values). Using gcc 4.8.5 and -std=c++11 (cannot
> change). The best code I could come up with so far is below.
>
> Taking the below code as an example, I want generated `callMethod'
> to have exactly same last 2 parameter types as the interface
> method it calls ((I,I) for ma, (const I&, const I&) for mb and
> (const I&, I) for mc). [...]
I took a pretty long look at this. I think you're up against a
hard problem. Here's the best I came up with (please excuse
some minor changes in names, etc):
template< typename T, const int >
class Caller {
T &worker;
public:
Caller( T &w ) : worker( w ) {}
template< typename ... Stuff > void
invoke( void (T::*pmf)( Stuff ... ), Stuff ... stuff ){
(worker.*pmf)( stuff ... );
}
};
and in main(), instead of
Caller<IA,1>(a).callMethod( &IA::ma, i1, i2 );
Caller<IA,2>(a).callMethod( &IA::mb, i3, i4 );
Caller<IA,3>(a).callMethod( &IA::mc, i5, i6 );
I have
Caller<IA,1>(a).invoke< I , I >( &IA::ma, i1, i2 );
Caller<IA,2>(a).invoke< const I &, const I & >( &IA::mb, i3, i4 );
Caller<IA,3>(a).invoke< const I &, I >( &IA::mc, i5, i6 );
I looked at using forward(), but I don't think it helps you. I
should add though that I'm still pretty much of a novice with
those things.
My sense is that you will be stuck with having to give the
template argument types explicitly rather than having them be
deduced. I have a similar disclaimer about not having any
level of expertise in template type deduction.
[toc] | [prev] | [next] | [standalone]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-06 23:48 -0400 |
| Message-ID | <vMFcF.70886$Fz3.63962@fx29.iad> |
| In reply to | #68255 |
Tim Rentsch wrote:
> Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
>
>> Trying to write generic code for forwarding arguments via a
>> template method to methods defined in an interface precisely (in
>> particular, all references should be forwarded as references and
>> values as values). Using gcc 4.8.5 and -std=c++11 (cannot
>> change). The best code I could come up with so far is below.
>>
>> Taking the below code as an example, I want generated `callMethod'
>> to have exactly same last 2 parameter types as the interface
>> method it calls ((I,I) for ma, (const I&, const I&) for mb and
>> (const I&, I) for mc). [...]
>
> I took a pretty long look at this. I think you're up against a
> hard problem. Here's the best I came up with (please excuse
> some minor changes in names, etc):
>
> template< typename T, const int >
> class Caller {
> T &worker;
> public:
> Caller( T &w ) : worker( w ) {}
>
> template< typename ... Stuff > void
> invoke( void (T::*pmf)( Stuff ... ), Stuff ... stuff ){
> (worker.*pmf)( stuff ... );
> }
> };
>
> and in main(), instead of
>
> Caller<IA,1>(a).callMethod( &IA::ma, i1, i2 );
> Caller<IA,2>(a).callMethod( &IA::mb, i3, i4 );
> Caller<IA,3>(a).callMethod( &IA::mc, i5, i6 );
>
> I have
>
> Caller<IA,1>(a).invoke< I , I >( &IA::ma, i1, i2 );
> Caller<IA,2>(a).invoke< const I &, const I & >( &IA::mb, i3, i4 );
> Caller<IA,3>(a).invoke< const I &, I >( &IA::mc, i5, i6 );
>
> I looked at using forward(), but I don't think it helps you. I
> should add though that I'm still pretty much of a novice with
> those things.
>
> My sense is that you will be stuck with having to give the
> template argument types explicitly rather than having them be
> deduced. I have a similar disclaimer about not having any
> level of expertise in template type deduction.
Thanks, I thought about it but wanted to avoid it if I could. I think I
will be able to resolve by-reference-vs-by-value issue specifically by
using some pattern on the argument, something like, in your terms,
invoke<some_type_calculation<Stuff>::type...>() and then maybe wrapping
it to a macro? But this of course sucks -- because of a macro and
because it would only take care of only one of transformations that
function template parameter substitution may do to the pack. I would
rather somehow extract the pack of argument types from method precisely
(this is what I am focusing on now, without much success so far). -Pavel
[toc] | [prev] | [next] | [standalone]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-07 10:16 -0400 |
| Subject | Problem solved: forward variable number of arguments precisely to a template method |
| Message-ID | <yZOcF.103013$9J3.42139@fx11.iad> |
| In reply to | #68143 |
I just realized the problem was solved (not by me but by a high-class
C++ expert who is a colleague of mine, to my luck). The below solution
works with gcc 4.8.5. The key is to apply "Identity" pattern to the
variable parameter type list and provide more information for type
deduction. The prototypes of generated callMethod member functions are
as below:
void Caller<IA, 1>::callMethod<I, I>(void (IA::*)(I, I),
Identity<I>::type, Identity<I>::type)
void Caller<IA, 2>::callMethod<I const&, I const&>(void (IA::*)(I
const&, I const&), Identity<I const&>::type, Identity<I const&>::type)
void Caller<IA, 3>::callMethod<I const&, I>(void (IA::*)(I const&, I),
Identity<I const&>::type, Identity<I>::type)
where Identity<T>::type is actually T so everything is to my satisfaction:
#include <iostream>
#include <functional>
using namespace std;
template<class M>
struct MethodTraits;
template<class T>
struct Identity {
using type = T;
};
struct I;
ostream& operator<<(ostream&, const I&);
struct I {
int i_;
I(int i): i_(i) {}
I(const I& i): i_(i.i_) {
cout << "I(c&" << i << ")\n";
}
I(I&& i): i_(i.i_) {
cout << "I(&&" << i << ")\n";
}
};
ostream&
operator<<(ostream& os, const I& i) { return os << i.i_; }
struct IA {
virtual void ma(I, I) = 0;
virtual void mb(const I&, const I&) = 0;
virtual void mc(const I&, I) = 0;
};
template <class T, const int>
struct Caller {
Caller(T& to): o(to) {}
T& o;
template<class... A>
void callMethod(void (T::*m)(A...), typename Identity<A>::type... args) {
(o.*m)(args...);
}
};
struct A: public IA {
void ma(I, I) override
{ cout << "A::ma(I, I)\n"; }
void mb(const I&, const I&) override
{ cout << "A::mb(const I& , const I&)\n"; }
void mc(const I&, I) override
{ cout << "A::mc(const I& , I)\n"; }
};
int
main(int, char*[])
{
A a;
const I i1{1};
const I i2{2};
I i3{3};
I i4{4};
const I i5{5};
const I i6{6};
Caller<IA, 1>(a).callMethod(&IA::ma, i1, i2);
Caller<IA, 2>(a).callMethod(&IA::mb, i3, i4);
Caller<IA, 3>(a).callMethod(&IA::mc, i5, i6);
return 0;
}
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2019-09-18 08:22 -0700 |
| Subject | Re: Problem solved: forward variable number of arguments precisely to a template method |
| Message-ID | <86ftkt4ok2.fsf@linuxsc.com> |
| In reply to | #68266 |
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> writes:
> I just realized the problem was solved (not by me but by a high-class
> C++ expert who is a colleague of mine, to my luck). The below solution
> works with gcc 4.8.5. The key is to apply "Identity" pattern to the
> variable parameter type list and provide more information for type
> deduction. [...]
>
> [ and the key part is ]
>
> template<class T>
> struct Identity {
> using type = T;
> };
>
> template <class T, const int>
> struct Caller {
> Caller(T& to): o(to) {}
> T& o;
> template<class... A>
> void callMethod(void (T::*m)(A...), typename Identity<A>::type... args) {
> (o.*m)(args...);
> }
> };
Interesting. It took me a while to figure out what's going on
and why this works. At first it looked exactly backwards, but
in retrospect it makes sense. Kudos to your colleague.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web