Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #68143 > unrolled thread

forward variable number of arguments precisely to a template method

Started byPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
First post2019-09-02 21:41 -0400
Last post2019-09-18 08:22 -0700
Articles 10 — 5 participants

Back to article view | Back to comp.lang.c++


Contents

  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

#68143 — forward variable number of arguments precisely to a template method

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-09-02 21:41 -0400
Subjectforward 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]


#68154

FromÖö Tiib <ootiib@hot.ee>
Date2019-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]


#68217

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-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]


#68234

FromManfred <noname@add.invalid>
Date2019-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]


#68183

FromVir Campestris <vir.campestris@invalid.invalid>
Date2019-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]


#68218

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-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]


#68255

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2019-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]


#68263

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-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]


#68266 — Problem solved: forward variable number of arguments precisely to a template method

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-09-07 10:16 -0400
SubjectProblem 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]


#68500 — Re: Problem solved: forward variable number of arguments precisely to a template method

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2019-09-18 08:22 -0700
SubjectRe: 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