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


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

Templated Casting operators

Started byNarinder <narinder.claire@gmail.com>
First post2011-07-07 16:34 -0700
Last post2011-07-10 12:03 +0200
Articles 20 — 4 participants

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


Contents

  Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-07 16:34 -0700
    Re: Templated Casting operators Alexander Bartolich <alexander.bartolich@gmx.at> - 2011-07-08 00:58 +0000
      Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-07 22:36 -0700
        Re: Templated Casting operators Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-07-08 09:42 +0200
          Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-08 01:16 -0700
            Re: Templated Casting operators Ian Collins <ian-news@hotmail.com> - 2011-07-08 20:23 +1200
          Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-08 01:37 -0700
            Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-08 06:28 -0700
          Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-08 01:40 -0700
            Re: Templated Casting operators Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-07-09 00:06 +0200
              Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-09 03:16 -0700
                Re: Templated Casting operators Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-07-09 13:34 +0200
                  Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-09 07:18 -0700
                    Re: Templated Casting operators Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-07-10 01:15 +0200
                      Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-09 21:39 -0700
                        Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-09 22:01 -0700
                          Re: Templated Casting operators Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-07-10 13:43 +0200
                            Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-10 05:55 -0700
                        Re: Templated Casting operators Narinder <narinder.claire@gmail.com> - 2011-07-10 00:19 -0700
                        Re: Templated Casting operators Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-07-10 12:03 +0200

#7621 — Templated Casting operators

FromNarinder <narinder.claire@gmail.com>
Date2011-07-07 16:34 -0700
SubjectTemplated Casting operators
Message-ID<8890cd86-3471-4b20-816a-82e27d2ebed0@d7g2000vbv.googlegroups.com>
Hello,
Can someone explain what should be the correct behaviour of the
following code:
__________________________________
#include<iostream>
using namespace std;
struct klass
{
        template<class T>
        operator T&()
        {
                throw("I am NON-const version");
        }
        template<class T>
        operator const T&()
        {
                throw("I am CONST version");
        }
};

int main()
{
        try
        {
                klass k;
                double x = k;
        }
        catch(const char *err)
        {
                cout << err << endl;
        }
}

__________________________________
Compiled with MSVC 2010, language extensions disabled I get the
output: "I am CONST version"
Compiled with gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)  with
command line 'g++ -pedantic -ansi'  I get the output  :"I am NON-
const
version"
Thanks in advance.
N

[toc] | [next] | [standalone]


#7623

FromAlexander Bartolich <alexander.bartolich@gmx.at>
Date2011-07-08 00:58 +0000
Message-ID<iv5ko1$3qb$1@news.albasani.net>
In reply to#7621
Narinder wrote:
> [...]
> Can someone explain what should be the correct behaviour of the
> following code:

Two functions in the same scope that differ only by return type?
My guess is that the behaviour is implementation defined.

> struct klass
> {
>         template<class T>
>         operator T&()
>         {
>                 throw("I am NON-const version");
>         }
>         template<class T>
>         operator const T&()
>         {
>                 throw("I am CONST version");
>         }
> };

The second signature is missing a trailing "const":

          operator const T&() const

-- 
host -t mx moderators.isc.org

[toc] | [prev] | [next] | [standalone]


#7626

FromNarinder <narinder.claire@gmail.com>
Date2011-07-07 22:36 -0700
Message-ID<8edcf612-c6e3-492b-b923-d418a9b8a1ab@s17g2000yqs.googlegroups.com>
In reply to#7623
On Jul 8, 1:58 am, Alexander Bartolich <alexander.bartol...@gmx.at>
wrote:
> Narinder wrote:
> > [...]
> > Can someone explain what should be the correct behaviour of the
> > following code:
>
> Two functions in the same scope that differ only by return type?
> My guess is that the behaviour is implementation defined.
>
> > struct klass
> > {
> >         template<class T>
> >         operator T&()
> >         {
> >                 throw("I am NON-const version");
> >         }
> >         template<class T>
> >         operator const T&()
> >         {
> >                 throw("I am CONST version");
> >         }
> > };
>
> The second signature is missing a trailing "const":
>
>           operator const T&() const
>
> --
> host -t mx moderators.isc.org

I think if the behaviour is 'supposed' to be implementation-defined,
then that is a problem, isn't it ?
Consider the following code:

-------------------------------------------------------------

#include<iostream>
using namespace std;

double pi =3.142;

struct klass
{

	template<class T>
	operator T&()
	{
		cout << "I am NON-const version\n";
		return pi;
	}

	template<class T>
	operator const T&()const
	{
		cout << "I am CONST version\n";
		return pi;
	}


};

template<class T>
T& show(T &t)
{
	cout << "NON-CONST show\n";
	return t;
}

template<class T>
const T& show(const T &t)
{
	cout << "CONST show\n";
	return t;
}

int main()
{

	klass k;
	show(k);
	show(klass());

	double x1 = k;
	double x2 = klass();

}

-----------------------------------------------------

Output from msvc :
NON-CONST show
CONST show
I am CONST version
I am CONST version

Output from gcc
NON-CONST show
CONST show
I am NON-CONST version
I am NON-CONST version

To me the msvc appears 'correct' or at least self-consistent. Or
perhaps I am missing something.

Any thoughts ?



[toc] | [prev] | [next] | [standalone]


#7634

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-07-08 09:42 +0200
Message-ID<iv6cds$a0f$1@hoshi.visyn.net>
In reply to#7626
Narinder wrote:

[...]
> Consider the following code:
> 
> -------------------------------------------------------------
> 
> #include<iostream>
> using namespace std;
> 
> double pi =3.142;
> 
> struct klass
> {
> 
> template<class T>
> operator T&()
> {
> cout << "I am NON-const version\n";
> return pi;
> }
> 
> template<class T>
> operator const T&()const
> {
> cout << "I am CONST version\n";
> return pi;
> }
> 
> 
> };
> 
> template<class T>
> T& show(T &t)
> {
> cout << "NON-CONST show\n";
> return t;
> }
> 
> template<class T>
> const T& show(const T &t)
> {
> cout << "CONST show\n";
> return t;
> }
> 
> int main()
> {
> 
> klass k;
> show(k);
> show(klass());
> 
> double x1 = k;
> double x2 = klass();
> 
> }
> 
> -----------------------------------------------------
> 
> Output from msvc :
> NON-CONST show
> CONST show
> I am CONST version
> I am CONST version
> 
> Output from gcc
> NON-CONST show
> CONST show
> I am NON-CONST version
> I am NON-CONST version
> 
> To me the msvc appears 'correct' or at least self-consistent. Or
> perhaps I am missing something.
> 
> Any thoughts ?

I think, gcc gets it right and lets you observe a language quirk: In this 
version, the two conversion operators differ by constness. Thus, overload 
resolution should be based on constness of the klass object being converted:

  klass k; // declares a non-const klass object k
  show(k); // should choose the T& version
  show( klass() ); // should choose the T const & version because of 8.5.3/5
  double x1 = k; // should choose the non-const member as k is non-const
  double x2 = klass(); // should choose the non-const member as the 
                       // temporary klass() is non-const

The last issue is an inconsistency in the language: though klass() is non-
const, the temporary cannot be used to initialize a non-const reference.


Best,

Kai-Uwe Bux

[toc] | [prev] | [next] | [standalone]


#7636

FromNarinder <narinder.claire@gmail.com>
Date2011-07-08 01:16 -0700
Message-ID<da0363c1-396f-4bf2-87c3-38f3121bf3f4@a31g2000vbt.googlegroups.com>
In reply to#7634
On Jul 8, 8:42 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Narinder wrote:
>
> [...]
>
>
>
>
>
> > Consider the following code:
>
> > -------------------------------------------------------------
>
> > #include<iostream>
> > using namespace std;
>
> > double pi =3.142;
>
> > struct klass
> > {
>
> > template<class T>
> > operator T&()
> > {
> > cout << "I am NON-const version\n";
> > return pi;
> > }
>
> > template<class T>
> > operator const T&()const
> > {
> > cout << "I am CONST version\n";
> > return pi;
> > }
>
> > };
>
> > template<class T>
> > T& show(T &t)
> > {
> > cout << "NON-CONST show\n";
> > return t;
> > }
>
> > template<class T>
> > const T& show(const T &t)
> > {
> > cout << "CONST show\n";
> > return t;
> > }
>
> > int main()
> > {
>
> > klass k;
> > show(k);
> > show(klass());
>
> > double x1 = k;
> > double x2 = klass();
>
> > }
>
> > -----------------------------------------------------
>
> > Output from msvc :
> > NON-CONST show
> > CONST show
> > I am CONST version
> > I am CONST version
>
> > Output from gcc
> > NON-CONST show
> > CONST show
> > I am NON-CONST version
> > I am NON-CONST version
>
> > To me the msvc appears 'correct' or at least self-consistent. Or
> > perhaps I am missing something.
>
> > Any thoughts ?
>
> I think, gcc gets it right and lets you observe a language quirk: In this
> version, the two conversion operators differ by constness. Thus, overload
> resolution should be based on constness of the klass object being converted:
>
>   klass k; // declares a non-const klass object k
>   show(k); // should choose the T& version
>   show( klass() ); // should choose the T const & version because of 8.5.3/5
>   double x1 = k; // should choose the non-const member as k is non-const
>   double x2 = klass(); // should choose the non-const member as the
>                        // temporary klass() is non-const
>
> The last issue is an inconsistency in the language: though klass() is non-
> const, the temporary cannot be used to initialize a non-const reference.
>
> Best,
>
> Kai-Uwe Bux

Hi
Thanks for the reply.

I was under the impress that a temporary variable would be cast only
as a
const &, which would make sense.

I find the output of the following code :

--------------------------------------------------------------
#include<iostream>
using namespace std;

double pi = 3.142;
struct klass
{

       template<class T>
       operator T&()
       {
               cout << "I am NON-const version\n";
               return pi;
       }

       template<class T>
       operator const T&()
       {
               cout << "I am CONST version\n";
               return pi;
       }
};

int main()
{

       klass k;
       double &x = k;
       const double &const_x = k;

}

-------------------------------------------------------------


more 'intuitivley' correct with msvc.
I am NON-const version
I am CONST version


than gcc
I am NON-const version
I am NON-const version

[toc] | [prev] | [next] | [standalone]


#7637

FromIan Collins <ian-news@hotmail.com>
Date2011-07-08 20:23 +1200
Message-ID<97nt5kF6tbU4@mid.individual.net>
In reply to#7636
On 07/ 8/11 08:16 PM, Narinder wrote:
> On Jul 8, 8:42 am, Kai-Uwe Bux<jkherci...@gmx.net>  wrote:
>>
>> I think, gcc gets it right and lets you observe a language quirk: In this
>> version, the two conversion operators differ by constness. Thus, overload
>> resolution should be based on constness of the klass object being converted:
>>
>>    klass k; // declares a non-const klass object k
>>    show(k); // should choose the T&  version
>>    show( klass() ); // should choose the T const&  version because of 8.5.3/5
>>    double x1 = k; // should choose the non-const member as k is non-const
>>    double x2 = klass(); // should choose the non-const member as the
>>                         // temporary klass() is non-const
>>
>> The last issue is an inconsistency in the language: though klass() is non-
>> const, the temporary cannot be used to initialize a non-const reference.
>>
>> Best,
>>
>> Kai-Uwe Bux
>
> Hi
> Thanks for the reply.
>
> I was under the impress that a temporary variable would be cast only
> as a
> const&, which would make sense.
>
> I find the output of the following code :
>
> --------------------------------------------------------------
> #include<iostream>
> using namespace std;
>
> double pi = 3.142;
> struct klass
> {
>
>         template<class T>
>         operator T&()
>         {
>                 cout<<  "I am NON-const version\n";
>                 return pi;
>         }
>
>         template<class T>
>         operator const T&()
>         {
>                 cout<<  "I am CONST version\n";
>                 return pi;
>         }
> };
>
> int main()
> {
>
>         klass k;
>         double&x = k;
>         const double&const_x = k;
>
> }
>
> -------------------------------------------------------------
>
>
> more 'intuitivley' correct with msvc.
> I am NON-const version
> I am CONST version
>
>
> than gcc
> I am NON-const version
> I am NON-const version

I think gcc is correct because k is non-const.

With gcc 4.5.1, I get

I am NON-const version
I am CONST version

So there must have been a recent change.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#7639

FromNarinder <narinder.claire@gmail.com>
Date2011-07-08 01:37 -0700
Message-ID<2c296cd6-62f1-44e8-a2c4-07bfb2b539db@u2g2000yqb.googlegroups.com>
In reply to#7634
On Jul 8, 8:42 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Narinder wrote:
>
> [...]
>
>
>
>
>
> > Consider the following code:
>
> > -------------------------------------------------------------
>
> > #include<iostream>
> > using namespace std;
>
> > double pi =3.142;
>
> > struct klass
> > {
>
> > template<class T>
> > operator T&()
> > {
> > cout << "I am NON-const version\n";
> > return pi;
> > }
>
> > template<class T>
> > operator const T&()const
> > {
> > cout << "I am CONST version\n";
> > return pi;
> > }
>
> > };
>
> > template<class T>
> > T& show(T &t)
> > {
> > cout << "NON-CONST show\n";
> > return t;
> > }
>
> > template<class T>
> > const T& show(const T &t)
> > {
> > cout << "CONST show\n";
> > return t;
> > }
>
> > int main()
> > {
>
> > klass k;
> > show(k);
> > show(klass());
>
> > double x1 = k;
> > double x2 = klass();
>
> > }
>
> > -----------------------------------------------------
>
> > Output from msvc :
> > NON-CONST show
> > CONST show
> > I am CONST version
> > I am CONST version
>
> > Output from gcc
> > NON-CONST show
> > CONST show
> > I am NON-CONST version
> > I am NON-CONST version
>
> > To me the msvc appears 'correct' or at least self-consistent. Or
> > perhaps I am missing something.
>
> > Any thoughts ?
>
> I think, gcc gets it right and lets you observe a language quirk: In this
> version, the two conversion operators differ by constness. Thus, overload
> resolution should be based on constness of the klass object being converted:
>
>   klass k; // declares a non-const klass object k
>   show(k); // should choose the T& version
>   show( klass() ); // should choose the T const & version because of 8.5.3/5
>   double x1 = k; // should choose the non-const member as k is non-const
>   double x2 = klass(); // should choose the non-const member as the
>                        // temporary klass() is non-const
>
> The last issue is an inconsistency in the language: though klass() is non-
> const, the temporary cannot be used to initialize a non-const reference.
>
> Best,
>
> Kai-Uwe Bux

Hi,

Thanks for the reply,

For the following code:

---------------------------------

#include<iostream>
using namespace std;

double pi = 3.142;
struct klass
{

       template<class T>
       operator T&()
       {
               cout << "I am NON-const version\n";
               return pi;
       }

       template<class T>
       operator const T&()
       {
               cout << "I am CONST version\n";
               return pi;
       }
};

int main()
{

       klass k;
       double x = k;
       double x2 = klass();

}

---------------------------------

msvc =>
I am CONST version
I am CONST version

and gcc =>
I am NON-const version
I am NON-const version

Which one would you say adhere's to language correctness and which one
is
desired ?

N


[toc] | [prev] | [next] | [standalone]


#7644

FromNarinder <narinder.claire@gmail.com>
Date2011-07-08 06:28 -0700
Message-ID<146d31d3-4f14-4be7-a2eb-65e0440b71ea@v7g2000vbk.googlegroups.com>
In reply to#7639
On Jul 8, 9:37 am, Narinder <narinder.cla...@gmail.com> wrote:
> On Jul 8, 8:42 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>
>
>
>
>
> > Narinder wrote:
>
> > [...]
>
> > > Consider the following code:
>
> > > -------------------------------------------------------------
>
> > > #include<iostream>
> > > using namespace std;
>
> > > double pi =3.142;
>
> > > struct klass
> > > {
>
> > > template<class T>
> > > operator T&()
> > > {
> > > cout << "I am NON-const version\n";
> > > return pi;
> > > }
>
> > > template<class T>
> > > operator const T&()const
> > > {
> > > cout << "I am CONST version\n";
> > > return pi;
> > > }
>
> > > };
>
> > > template<class T>
> > > T& show(T &t)
> > > {
> > > cout << "NON-CONST show\n";
> > > return t;
> > > }
>
> > > template<class T>
> > > const T& show(const T &t)
> > > {
> > > cout << "CONST show\n";
> > > return t;
> > > }
>
> > > int main()
> > > {
>
> > > klass k;
> > > show(k);
> > > show(klass());
>
> > > double x1 = k;
> > > double x2 = klass();
>
> > > }
>
> > > -----------------------------------------------------
>
> > > Output from msvc :
> > > NON-CONST show
> > > CONST show
> > > I am CONST version
> > > I am CONST version
>
> > > Output from gcc
> > > NON-CONST show
> > > CONST show
> > > I am NON-CONST version
> > > I am NON-CONST version
>
> > > To me the msvc appears 'correct' or at least self-consistent. Or
> > > perhaps I am missing something.
>
> > > Any thoughts ?
>
> > I think, gcc gets it right and lets you observe a language quirk: In this
> > version, the two conversion operators differ by constness. Thus, overload
> > resolution should be based on constness of the klass object being converted:
>
> >   klass k; // declares a non-const klass object k
> >   show(k); // should choose the T& version
> >   show( klass() ); // should choose the T const & version because of 8.5.3/5
> >   double x1 = k; // should choose the non-const member as k is non-const
> >   double x2 = klass(); // should choose the non-const member as the
> >                        // temporary klass() is non-const
>
> > The last issue is an inconsistency in the language: though klass() is non-
> > const, the temporary cannot be used to initialize a non-const reference.
>
> > Best,
>
> > Kai-Uwe Bux
>
> Hi,
>
> Thanks for the reply,
>
> For the following code:
>
> ---------------------------------
>
> #include<iostream>
> using namespace std;
>
> double pi = 3.142;
> struct klass
> {
>
>        template<class T>
>        operator T&()
>        {
>                cout << "I am NON-const version\n";
>                return pi;
>        }
>
>        template<class T>
>        operator const T&()
>        {
>                cout << "I am CONST version\n";
>                return pi;
>        }
>
> };
>
> int main()
> {
>
>        klass k;
>        double x = k;
>        double x2 = klass();
>
> }
>
> ---------------------------------
>
> msvc =>
> I am CONST version
> I am CONST version
>
> and gcc =>
> I am NON-const version
> I am NON-const version
>
> Which one would you say adhere's to language correctness and which one
> is
> desired ?
>
> N

Hello,

To elaborate on this a little more, I'll  put the issue that I have in
a
context more closer to my actual scenario.
The following code compiles and executes fine under msvc but throws
under
gcc.  I think the behaviour under gcc is much less desirable. I am
curious
about the language's rationale behind this:

---------------------------------------------------
#include<iostream>
#include<boost/ref.hpp>
#include<boost/variant.hpp>
using namespace std;

double pi = 3.142;

typedef boost::reference_wrapper<double>  ref;
typedef boost::reference_wrapper<const double>  const_ref;

struct klass
{
       klass(double & x):innerVariant(boost::ref(x)){}
       klass(const double & x):innerVariant(boost::cref(x)){}

       template<class T>
       operator T&()
       {
               cout << "Attempting  non-const cast .... ";
               return boost::get<ref >(innerVariant);
       }

       template<class T>
       operator const T&()
       {
               cout << "Attempting  const cast .... ";
               if(boost::get<ref >(&innerVariant))
               {
                       return boost::get<ref >(innerVariant);
               }
               return boost::get<const_ref >(innerVariant);
       }

private:
       boost::variant<ref,const_ref >  innerVariant;
};

void f(double &x)
{
       cout << "double &x\n";
}
void fc(const double &x)
{
       cout << "const double &x\n";
}
void ft(double x)
{
       cout << "double\n";
}
int main()
{

       try
       {
       double x(3.142);
       klass k_non_const(x);
       klass k_const(3.142);

       f(k_non_const);
       fc(k_non_const);
       ft(k_non_const);

       fc(k_const);
       ft(k_const); // this one throws with gcc
       }
       catch(const std::exception &err)
       {
               cout << err.what() << "\n";
       }

}

-----------------------------------------------


N

[toc] | [prev] | [next] | [standalone]


#7640

FromNarinder <narinder.claire@gmail.com>
Date2011-07-08 01:40 -0700
Message-ID<8aed9603-26d2-41fb-b197-213bdf90ff99@34g2000yqr.googlegroups.com>
In reply to#7634
On Jul 8, 8:42 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Narinder wrote:
>
> [...]
>
>
>
>
>
> > Consider the following code:
>
> > -------------------------------------------------------------
>
> > #include<iostream>
> > using namespace std;
>
> > double pi =3.142;
>
> > struct klass
> > {
>
> > template<class T>
> > operator T&()
> > {
> > cout << "I am NON-const version\n";
> > return pi;
> > }
>
> > template<class T>
> > operator const T&()const
> > {
> > cout << "I am CONST version\n";
> > return pi;
> > }
>
> > };
>
> > template<class T>
> > T& show(T &t)
> > {
> > cout << "NON-CONST show\n";
> > return t;
> > }
>
> > template<class T>
> > const T& show(const T &t)
> > {
> > cout << "CONST show\n";
> > return t;
> > }
>
> > int main()
> > {
>
> > klass k;
> > show(k);
> > show(klass());
>
> > double x1 = k;
> > double x2 = klass();
>
> > }
>
> > -----------------------------------------------------
>
> > Output from msvc :
> > NON-CONST show
> > CONST show
> > I am CONST version
> > I am CONST version
>
> > Output from gcc
> > NON-CONST show
> > CONST show
> > I am NON-CONST version
> > I am NON-CONST version
>
> > To me the msvc appears 'correct' or at least self-consistent. Or
> > perhaps I am missing something.
>
> > Any thoughts ?
>
> I think, gcc gets it right and lets you observe a language quirk: In this
> version, the two conversion operators differ by constness. Thus, overload
> resolution should be based on constness of the klass object being converted:
>
>   klass k; // declares a non-const klass object k
>   show(k); // should choose the T& version
>   show( klass() ); // should choose the T const & version because of 8.5.3/5
>   double x1 = k; // should choose the non-const member as k is non-const
>   double x2 = klass(); // should choose the non-const member as the
>                        // temporary klass() is non-const
>
> The last issue is an inconsistency in the language: though klass() is non-
> const, the temporary cannot be used to initialize a non-const reference.
>
> Best,
>
> Kai-Uwe Bux

Hi,

Thanks for the reply,

For the following code:

---------------------------------

#include<iostream>
using namespace std;

double pi = 3.142;
struct klass
{

       template<class T>
       operator T&()
       {
               cout << "I am NON-const version\n";
               return pi;
       }

       template<class T>
       operator const T&()
       {
               cout << "I am CONST version\n";
               return pi;
       }
};

int main()
{

       klass k;
       double x = k;
       double x2 = klass();

}

---------------------------------

msvc =>
I am CONST version
I am CONST version

and gcc =>
I am NON-const version
I am NON-const version

Which one would you say adhere's to language correctness and which one
is
desired ?

N

[toc] | [prev] | [next] | [standalone]


#7660

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-07-09 00:06 +0200
Message-ID<iv7v24$oo9$1@hoshi.visyn.net>
In reply to#7640
Narinder wrote:

> On Jul 8, 8:42 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>> Narinder wrote:
>>
>> [...]
>>
>>
>>
>>
>>
>> > Consider the following code:
>>
>> > -------------------------------------------------------------
>>
>> > #include<iostream>
>> > using namespace std;
>>
>> > double pi =3.142;
>>
>> > struct klass
>> > {
>>
>> > template<class T>
>> > operator T&()
>> > {
>> > cout << "I am NON-const version\n";
>> > return pi;
>> > }
>>
>> > template<class T>
>> > operator const T&()const
>> > {
>> > cout << "I am CONST version\n";
>> > return pi;
>> > }
>>
>> > };
>>
>> > template<class T>
>> > T& show(T &t)
>> > {
>> > cout << "NON-CONST show\n";
>> > return t;
>> > }
>>
>> > template<class T>
>> > const T& show(const T &t)
>> > {
>> > cout << "CONST show\n";
>> > return t;
>> > }
>>
>> > int main()
>> > {
>>
>> > klass k;
>> > show(k);
>> > show(klass());
>>
>> > double x1 = k;
>> > double x2 = klass();
>>
>> > }
>>
>> > -----------------------------------------------------
>>
>> > Output from msvc :
>> > NON-CONST show
>> > CONST show
>> > I am CONST version
>> > I am CONST version
>>
>> > Output from gcc
>> > NON-CONST show
>> > CONST show
>> > I am NON-CONST version
>> > I am NON-CONST version
>>
>> > To me the msvc appears 'correct' or at least self-consistent. Or
>> > perhaps I am missing something.
>>
>> > Any thoughts ?
>>
>> I think, gcc gets it right and lets you observe a language quirk: In this
>> version, the two conversion operators differ by constness. Thus, overload
>> resolution should be based on constness of the klass object being
>> converted:
>>
>> klass k; // declares a non-const klass object k
>> show(k); // should choose the T& version
>> show( klass() ); // should choose the T const & version because of
>> 8.5.3/5 double x1 = k; // should choose the non-const member as k is
>> non-const double x2 = klass(); // should choose the non-const member as
>> the // temporary klass() is non-const
>>
>> The last issue is an inconsistency in the language: though klass() is
>> non- const, the temporary cannot be used to initialize a non-const
>> reference.
>>
>> Best,
>>
>> Kai-Uwe Bux
> 
> Hi,
> 
> Thanks for the reply,
> 
> For the following code:
> 
> ---------------------------------
> 
> #include<iostream>
> using namespace std;
> 
> double pi = 3.142;
> struct klass
> {
> 
> template<class T>
> operator T&()
> {
> cout << "I am NON-const version\n";
> return pi;
> }
> 
> template<class T>
> operator const T&()
> {
> cout << "I am CONST version\n";
> return pi;
> }
> };
> 
> int main()
> {
> 
> klass k;
> double x = k;
> double x2 = klass();
> 
> }
> 
> ---------------------------------
> 
> msvc =>
> I am CONST version
> I am CONST version
> 
> and gcc =>
> I am NON-const version
> I am NON-const version
> 
> Which one would you say adhere's to language correctness and which one
> is
> desired ?

I would expect a compilation error due to ambiguity. The code seems to be 
just a template version of something like this:

class k {

  double value;

public:

  k ( double v )
    : value ( v )
  {}

  operator double & ( void ) {
    std::cout << "non-const\n";
    return ( value );
  }

  operator double const & ( void ) {
    std::cout << "const\n";
    return ( value );
  }

};

int main ( void ) {
  k x ( 13.4 );
  double a = x;
  double const b = x;
}

Here, you get a compilation error. I wonder why you don't with templates: 
even Comeau compiles the template version. From the test case

#include <iostream>

template < typename T >
struct oops;

class k {

  double value;

public:

  k ( double v )
    : value ( v )
  {}

  template < typename T >
  operator T & ( void ) {
    std::cout << "non-const\n";
    return ( value );
  }

  template < typename T >
  operator T const & ( void ) {
    oops<T>::value;
    std::cout << "const\n";
    return ( value );
  }

};

int main ( void ) {
  k x ( 13.4 );
  double a = x;
  double const b = x;
}

and the version, where oops<T>::value is placed into the non-const version, 
one can see that Comeau (like gcc) instantiates only the operator T& 
template. At the moment, I don't see why.


Best,

Kai-Uwe Bux

[toc] | [prev] | [next] | [standalone]


#7679

FromNarinder <narinder.claire@gmail.com>
Date2011-07-09 03:16 -0700
Message-ID<f966f5b5-a173-45f5-b1ea-035ca5977502@n5g2000yqh.googlegroups.com>
In reply to#7660
>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>At the moment, I don't see why.

That is indeed curious.
However on my issue, I think I am expecting something from C++ .. when
I obviously should know better,  "C++ (101): C++ doesn't dispatch on
the return type".

My question stems from wanting to pass parameters to a function via an
intermediary which holds references to the values to be passed. And
this would be done at runtime.

Given :

void f( double x);


I want to be able to do:

const double x=3.142;
intermediary v = x; // so v will hold a
std::tr1::reference_wrapper<const double>
f(v);               // I suspect gcc will complain because v is unable
to give up its const ref
                    // but as we have seen gcc calls operator
double&()


My way around this will be to have the user provide a precise boost
typelist embodying the function signature:

boost::mpl::vector<double>

and use this to dispatch correctly.

Thanks for your all your help.

Best Regards
N




[toc] | [prev] | [next] | [standalone]


#7680

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-07-09 13:34 +0200
Message-ID<iv9ed1$67q$1@hoshi.visyn.net>
In reply to#7679
Narinder wrote:

>>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>>At the moment, I don't see why.
> 
> That is indeed curious.
> However on my issue, I think I am expecting something from C++ .. when
> I obviously should know better,  "C++ (101): C++ doesn't dispatch on
> the return type".

That, I think, is not the entire picture. There is clause [14.8.2.3] that 
deals with deducing template arguments for templated conversion operators. 
Here, the result type desired by the conversion is taken into account. 
Howerver, reading that clause, I find it hard to tell whether the deduction 
should fail because of ambiguity, whether the const version should be 
instantiated, or whether the non-const version should be chosen.

 
> My question stems from wanting to pass parameters to a function via an
> intermediary which holds references to the values to be passed. And
> this would be done at runtime.
> 
> Given :
> 
> void f( double x);
> 
> 
> I want to be able to do:
> 
> const double x=3.142;
> intermediary v = x; // so v will hold a
> std::tr1::reference_wrapper<const double>
> f(v);               // I suspect gcc will complain because v is unable
> to give up its const ref
>                     // but as we have seen gcc calls operator
> double&()

Hm, the following compiles:

#include <iostream>

void foo ( double arg ) {
  std::cout << arg << "\n";
}

  template < typename T >
  class reference_wrapper {

    T* the_ptr;

  public:

    typedef T type;
    typedef T& reference;
    
    reference_wrapper ( reference t_ref )
      : the_ptr ( &t_ref )
    {}

    operator reference ( void ) {
      return ( *the_ptr );
    }

    reference get ( void ) {
      return ( *the_ptr );
    }

 };

int main ( void ) {
  double const pi = 3.14159;
  reference_wrapper< double const > x = pi;
  foo( x );
}

> My way around this will be to have the user provide a precise boost
> typelist embodying the function signature:
> 
> boost::mpl::vector<double>
> 
> and use this to dispatch correctly.

Huh?


Best,

Kai-Uwe Bux

[toc] | [prev] | [next] | [standalone]


#7682

FromNarinder <narinder.claire@gmail.com>
Date2011-07-09 07:18 -0700
Message-ID<b781d567-f97a-4951-b3fb-b6702884a8d8@h12g2000vbx.googlegroups.com>
In reply to#7680
On Jul 9, 12:34 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Narinder wrote:
> >>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> >>At the moment, I don't see why.
>
> > That is indeed curious.
> > However on my issue, I think I am expecting something from C++ .. when
> > I obviously should know better,  "C++ (101): C++ doesn't dispatch on
> > the return type".
>
> That, I think, is not the entire picture. There is clause [14.8.2.3] that
> deals with deducing template arguments for templated conversion operators.
> Here, the result type desired by the conversion is taken into account.
> Howerver, reading that clause, I find it hard to tell whether the deduction
> should fail because of ambiguity, whether the const version should be
> instantiated, or whether the non-const version should be chosen.
>
>
>
>
>
>
>
>
>
> > My question stems from wanting to pass parameters to a function via an
> > intermediary which holds references to the values to be passed. And
> > this would be done at runtime.
>
> > Given :
>
> > void f( double x);
>
> > I want to be able to do:
>
> > const double x=3.142;
> > intermediary v = x; // so v will hold a
> > std::tr1::reference_wrapper<const double>
> > f(v);               // I suspect gcc will complain because v is unable
> > to give up its const ref
> >                     // but as we have seen gcc calls operator
> > double&()
>
> Hm, the following compiles:
>
> #include <iostream>
>
> void foo ( double arg ) {
>   std::cout << arg << "\n";
>
> }
>
>   template < typename T >
>   class reference_wrapper {
>
>     T* the_ptr;
>
>   public:
>
>     typedef T type;
>     typedef T& reference;
>
>     reference_wrapper ( reference t_ref )
>       : the_ptr ( &t_ref )
>     {}
>
>     operator reference ( void ) {
>       return ( *the_ptr );
>     }
>
>     reference get ( void ) {
>       return ( *the_ptr );
>     }
>
>  };
>
> int main ( void ) {
>   double const pi = 3.14159;
>   reference_wrapper< double const > x = pi;
>   foo( x );
>
> }
> > My way around this will be to have the user provide a precise boost
> > typelist embodying the function signature:
>
> > boost::mpl::vector<double>
>
> > and use this to dispatch correctly.
>
> Huh?
>
> Best,
>
> Kai-Uwe Bux

Consider the following functions:

f_ref(double&)              // may be a member function that keeps the
rw ref
f_const_ref(const double&)  // maybe a memeber function that keeps the
ro ref
f_val(double)               // expects the value byval

you have one 'variant'

variant v = 3.142;

double x=3.142;
variant v2 = x;

const double xx=3.142
variant v3 = 3.142

I want to deliver (since it doesn't have to be done by casting) v2 to
f_ref, but not v & v3
I want to deliver v2 & v3 to f_const_ref but not v
and i want to be able to deliver all of them to f_val

Moreover my variants will be initialised at runtime.


I have sketched (but compiles and executes ) what I think is a
solution.
(I have used boost::mpl::vector to be able to generalise to more than
one parameter)

-------------------------------
#include<iostream>
#include<boost/ref.hpp>
#include<boost/variant.hpp>
#include<boost/mpl/vector.hpp>
#include<boost/mpl/at.hpp>


using namespace std;


double pi = 3.142;
typedef boost::reference_wrapper<double>  ref;
typedef boost::reference_wrapper<const double>  const_ref;

struct klass
{
    klass(double & x):innerVariant(boost::ref(x)){}
    klass(const double & x):innerVariant(boost::cref(x)){}

    template<class T>
    operator T& ()
    {
        cout << " ... casting to double&  ";
        return boost::get<ref>(innerVariant);
    }

    template<class T>
    operator const T&()
    {
        cout << " ... casting to const double&  ";
        if(boost::get<ref>(&innerVariant))
        {
            return boost::get<ref>(innerVariant);
        }
        return boost::get<const_ref>(innerVariant);

    }


    const double &get_by_val()
    {
        return (const double&)(*this);
    }


private:
    boost::variant<ref,const_ref >  innerVariant;
};

template<class T,class U>
struct innerCast
{
    static const T & get(U &k)
    {
        return k.get_by_val();
    }
};

template<class T,class U>
struct innerCast<T&,U>
{
    static T & get(U &k)
    {
        return k;
    }
};

template<class T,class U>
struct innerCast<const T&,U>
{
    static const T & get(U &k)
    {
        return k;
    }
};


template<class T>
struct cast
{
    typedef typename boost::mpl::at_c<typename T::param_type,0>::type
ret_type;

    static ret_type get(klass &k)
    {
        return innerCast<ret_type,klass>::get(k);
    }

};


/////////////////////////////////////////
// Below is what would be the user code
/////////////////////////////////////////

struct f
{
    typedef boost::mpl::vector<double&>::type param_type;
    static void call(double &x)
    {
        cout << " double &x\n";
    }
};

struct fc
{
    typedef boost::mpl::vector<const double&> param_type;
    static void call(const double &x)
    {
        cout << " const double &x\n";
    }
};

struct ft
{
    typedef boost::mpl::vector<double> param_type;
    static void call(double x)
    {
        cout << " double\n";
    }

};

int main()
{

    try
    {

        double x(3.142);

        klass k_non_const(x);
        klass k_const(3.142);

        f::call( cast<f>::get(k_non_const) );
        fc::call( cast<fc>::get(k_non_const));
        ft::call( cast<ft>::get(k_non_const));

        fc::call( cast<fc>::get(k_const));
        ft::call( cast<ft>::get(k_const)); // this one *NO LONGER*
throws with gcc
    }
    catch(const std::exception &err)
    {
        cout << err.what() << "\n";
    }

}

---------------------------------------------

Maybe some of the class names have alot of scope to be more
meaningful :-)


Best Regards
N








[toc] | [prev] | [next] | [standalone]


#7687

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-07-10 01:15 +0200
Message-ID<ivanek$g9k$1@hoshi.visyn.net>
In reply to#7682
Narinder wrote:

> On Jul 9, 12:34 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>> Narinder wrote:
>> >>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>> >>At the moment, I don't see why.
>>
>> > That is indeed curious.
>> > However on my issue, I think I am expecting something from C++ .. when
>> > I obviously should know better,  "C++ (101): C++ doesn't dispatch on
>> > the return type".
>>
>> That, I think, is not the entire picture. There is clause [14.8.2.3] that
>> deals with deducing template arguments for templated conversion
>> operators. Here, the result type desired by the conversion is taken into
>> account. Howerver, reading that clause, I find it hard to tell whether
>> the deduction should fail because of ambiguity, whether the const version
>> should be instantiated, or whether the non-const version should be
>> chosen.
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> > My question stems from wanting to pass parameters to a function via an
>> > intermediary which holds references to the values to be passed. And
>> > this would be done at runtime.
>>
>> > Given :
>>
>> > void f( double x);
>>
>> > I want to be able to do:
>>
>> > const double x=3.142;
>> > intermediary v = x; // so v will hold a
>> > std::tr1::reference_wrapper<const double>
>> > f(v);               // I suspect gcc will complain because v is unable
>> > to give up its const ref
>> > // but as we have seen gcc calls operator
>> > double&()
>>
>> Hm, the following compiles:
>>
>> #include <iostream>
>>
>> void foo ( double arg ) {
>> std::cout << arg << "\n";
>>
>> }
>>
>> template < typename T >
>> class reference_wrapper {
>>
>> T* the_ptr;
>>
>> public:
>>
>> typedef T type;
>> typedef T& reference;
>>
>> reference_wrapper ( reference t_ref )
>> : the_ptr ( &t_ref )
>> {}
>>
>> operator reference ( void ) {
>> return ( *the_ptr );
>> }
>>
>> reference get ( void ) {
>> return ( *the_ptr );
>> }
>>
>> };
>>
>> int main ( void ) {
>> double const pi = 3.14159;
>> reference_wrapper< double const > x = pi;
>> foo( x );
>>
>> }
>> > My way around this will be to have the user provide a precise boost
>> > typelist embodying the function signature:
>>
>> > boost::mpl::vector<double>
>>
>> > and use this to dispatch correctly.
>>
>> Huh?
>>
>> Best,
>>
>> Kai-Uwe Bux
> 
> Consider the following functions:
> 
> f_ref(double&)              // may be a member function that keeps the
> rw ref
> f_const_ref(const double&)  // maybe a memeber function that keeps the
> ro ref
> f_val(double)               // expects the value byval
> 
> you have one 'variant'
> 
> variant v = 3.142;
> 
> double x=3.142;
> variant v2 = x;
> 
> const double xx=3.142
> variant v3 = 3.142
> 
> I want to deliver (since it doesn't have to be done by casting) v2 to
> f_ref, but not v & v3
> I want to deliver v2 & v3 to f_const_ref but not v
> and i want to be able to deliver all of them to f_val
> 
> Moreover my variants will be initialised at runtime.
> 
> 
> I have sketched (but compiles and executes ) what I think is a
> solution.
> (I have used boost::mpl::vector to be able to generalise to more than
> one parameter)
> 
> -------------------------------
> #include<iostream>
> #include<boost/ref.hpp>
> #include<boost/variant.hpp>
> #include<boost/mpl/vector.hpp>
> #include<boost/mpl/at.hpp>
> 
> 
> using namespace std;
> 
> 
> double pi = 3.142;
> typedef boost::reference_wrapper<double>  ref;
> typedef boost::reference_wrapper<const double>  const_ref;
> 
> struct klass
> {
>     klass(double & x):innerVariant(boost::ref(x)){}
>     klass(const double & x):innerVariant(boost::cref(x)){}
> 
>     template<class T>
>     operator T& ()
>     {
>         cout << " ... casting to double&  ";
>         return boost::get<ref>(innerVariant);
>     }
> 
>     template<class T>
>     operator const T&()
>     {
>         cout << " ... casting to const double&  ";
>         if(boost::get<ref>(&innerVariant))
>         {
>             return boost::get<ref>(innerVariant);
>         }
>         return boost::get<const_ref>(innerVariant);
> 
>     }
> 
> 
>     const double &get_by_val()
>     {
>         return (const double&)(*this);
>     }
> 
> 
> private:
>     boost::variant<ref,const_ref >  innerVariant;
> };
> 
> template<class T,class U>
> struct innerCast
> {
>     static const T & get(U &k)
>     {
>         return k.get_by_val();
>     }
> };
> 
> template<class T,class U>
> struct innerCast<T&,U>
> {
>     static T & get(U &k)
>     {
>         return k;
>     }
> };
> 
> template<class T,class U>
> struct innerCast<const T&,U>
> {
>     static const T & get(U &k)
>     {
>         return k;
>     }
> };
> 
> 
> template<class T>
> struct cast
> {
>     typedef typename boost::mpl::at_c<typename T::param_type,0>::type
> ret_type;
> 
>     static ret_type get(klass &k)
>     {
>         return innerCast<ret_type,klass>::get(k);
>     }
> 
> };
> 
> 
> /////////////////////////////////////////
> // Below is what would be the user code
> /////////////////////////////////////////
> 
> struct f
> {
>     typedef boost::mpl::vector<double&>::type param_type;
>     static void call(double &x)
>     {
>         cout << " double &x\n";
>     }
> };
> 
> struct fc
> {
>     typedef boost::mpl::vector<const double&> param_type;
>     static void call(const double &x)
>     {
>         cout << " const double &x\n";
>     }
> };
> 
> struct ft
> {
>     typedef boost::mpl::vector<double> param_type;
>     static void call(double x)
>     {
>         cout << " double\n";
>     }
> 
> };
> 
> int main()
> {
> 
>     try
>     {
> 
>         double x(3.142);
> 
>         klass k_non_const(x);
>         klass k_const(3.142);
> 
>         f::call( cast<f>::get(k_non_const) );
>         fc::call( cast<fc>::get(k_non_const));
>         ft::call( cast<ft>::get(k_non_const));
> 
>         fc::call( cast<fc>::get(k_const));
>         ft::call( cast<ft>::get(k_const)); // this one *NO LONGER*
> throws with gcc
>     }
>     catch(const std::exception &err)
>     {
>         cout << err.what() << "\n";
>     }
> 
> }
> 
> ---------------------------------------------
> 
> Maybe some of the class names have alot of scope to be more
> meaningful :-)

Here is an alternative idea (hopefully, I understood your aim):

#include <iostream>

struct oops {};

template < typename T >
class const_reference {

  T const * ptr;
  
public:

  const_reference ( T const & r )
    : ptr ( &r )
  {}
  
  T const & get ( void ) {
    return ( *ptr );
  }

  operator T const & ( void ) {
    return ( *ptr );
  }
  
};

template < typename T >
class reference {

  T * ptr;
  
public:

  reference ( T & r )
    : ptr ( &r )
  {}
  
  T & get ( void ) {
    return ( *ptr );
  }

  operator T & ( void ) {
    return ( *ptr );
  }
  
};

template < typename T >
class wrapper {
private:

  T *       the_ptr;
  T const * the_c_ptr;
  
public:
  
  wrapper ( T & ref )
    : the_ptr ( &ref )
    , the_c_ptr ()
  {}

  wrapper ( T const & cref )
    : the_ptr ()
    , the_c_ptr ( &cref )
  {}
  
  operator reference<T> ( void ) {
    std::cout << "non-const\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    throw ( oops() );
  }

  operator const_reference<T> ( void ) {
    std::cout << "const\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    return ( *the_c_ptr );
  }

  operator T ( void ) {
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    return ( *the_c_ptr );
  }
  
};

double const pi = 3.14159;
double e = 2.71828;

typedef wrapper< double > klass;

void foo_ref ( reference<double> ) {
  std::cout << "reference\n";
}

void foo_cref ( const_reference<double> ) {
  std::cout << "const reference\n";
}

void foo_val ( double ) {
  std::cout << "value\n";
}

int main ( void ) {
  klass rw ( e );
  klass ro ( pi );
  foo_val( rw );
  foo_cref( rw );
  foo_ref( rw );
  foo_val( ro );
  foo_cref( ro );
  foo_ref( ro );
}


Best,

Kai-Uwe Bux

[toc] | [prev] | [next] | [standalone]


#7691

FromNarinder <narinder.claire@gmail.com>
Date2011-07-09 21:39 -0700
Message-ID<129c15d7-bb88-4a2c-a42e-c9292e491a8a@w4g2000yqm.googlegroups.com>
In reply to#7687
On Jul 10, 12:15 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Narinder wrote:
> > On Jul 9, 12:34 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> >> Narinder wrote:
> >> >>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> >> >>At the moment, I don't see why.
>
> >> > That is indeed curious.
> >> > However on my issue, I think I am expecting something from C++ .. when
> >> > I obviously should know better,  "C++ (101): C++ doesn't dispatch on
> >> > the return type".
>
> >> That, I think, is not the entire picture. There is clause [14.8.2.3] that
> >> deals with deducing template arguments for templated conversion
> >> operators. Here, the result type desired by the conversion is taken into
> >> account. Howerver, reading that clause, I find it hard to tell whether
> >> the deduction should fail because of ambiguity, whether the const version
> >> should be instantiated, or whether the non-const version should be
> >> chosen.
>
> >> > My question stems from wanting to pass parameters to a function via an
> >> > intermediary which holds references to the values to be passed. And
> >> > this would be done at runtime.
>
> >> > Given :
>
> >> > void f( double x);
>
> >> > I want to be able to do:
>
> >> > const double x=3.142;
> >> > intermediary v = x; // so v will hold a
> >> > std::tr1::reference_wrapper<const double>
> >> > f(v);               // I suspect gcc will complain because v is unable
> >> > to give up its const ref
> >> > // but as we have seen gcc calls operator
> >> > double&()
>
> >> Hm, the following compiles:
>
> >> #include <iostream>
>
> >> void foo ( double arg ) {
> >> std::cout << arg << "\n";
>
> >> }
>
> >> template < typename T >
> >> class reference_wrapper {
>
> >> T* the_ptr;
>
> >> public:
>
> >> typedef T type;
> >> typedef T& reference;
>
> >> reference_wrapper ( reference t_ref )
> >> : the_ptr ( &t_ref )
> >> {}
>
> >> operator reference ( void ) {
> >> return ( *the_ptr );
> >> }
>
> >> reference get ( void ) {
> >> return ( *the_ptr );
> >> }
>
> >> };
>
> >> int main ( void ) {
> >> double const pi = 3.14159;
> >> reference_wrapper< double const > x = pi;
> >> foo( x );
>
> >> }
> >> > My way around this will be to have the user provide a precise boost
> >> > typelist embodying the function signature:
>
> >> > boost::mpl::vector<double>
>
> >> > and use this to dispatch correctly.
>
> >> Huh?
>
> >> Best,
>
> >> Kai-Uwe Bux
>
> > Consider the following functions:
>
> > f_ref(double&)              // may be a member function that keeps the
> > rw ref
> > f_const_ref(const double&)  // maybe a memeber function that keeps the
> > ro ref
> > f_val(double)               // expects the value byval
>
> > you have one 'variant'
>
> > variant v = 3.142;
>
> > double x=3.142;
> > variant v2 = x;
>
> > const double xx=3.142
> > variant v3 = 3.142
>
> > I want to deliver (since it doesn't have to be done by casting) v2 to
> > f_ref, but not v & v3
> > I want to deliver v2 & v3 to f_const_ref but not v
> > and i want to be able to deliver all of them to f_val
>
> > Moreover my variants will be initialised at runtime.
>
> > I have sketched (but compiles and executes ) what I think is a
> > solution.
> > (I have used boost::mpl::vector to be able to generalise to more than
> > one parameter)
>
> > -------------------------------
> > #include<iostream>
> > #include<boost/ref.hpp>
> > #include<boost/variant.hpp>
> > #include<boost/mpl/vector.hpp>
> > #include<boost/mpl/at.hpp>
>
> > using namespace std;
>
> > double pi = 3.142;
> > typedef boost::reference_wrapper<double>  ref;
> > typedef boost::reference_wrapper<const double>  const_ref;
>
> > struct klass
> > {
> >     klass(double & x):innerVariant(boost::ref(x)){}
> >     klass(const double & x):innerVariant(boost::cref(x)){}
>
> >     template<class T>
> >     operator T& ()
> >     {
> >         cout << " ... casting to double&  ";
> >         return boost::get<ref>(innerVariant);
> >     }
>
> >     template<class T>
> >     operator const T&()
> >     {
> >         cout << " ... casting to const double&  ";
> >         if(boost::get<ref>(&innerVariant))
> >         {
> >             return boost::get<ref>(innerVariant);
> >         }
> >         return boost::get<const_ref>(innerVariant);
>
> >     }
>
> >     const double &get_by_val()
> >     {
> >         return (const double&)(*this);
> >     }
>
> > private:
> >     boost::variant<ref,const_ref >  innerVariant;
> > };
>
> > template<class T,class U>
> > struct innerCast
> > {
> >     static const T & get(U &k)
> >     {
> >         return k.get_by_val();
> >     }
> > };
>
> > template<class T,class U>
> > struct innerCast<T&,U>
> > {
> >     static T & get(U &k)
> >     {
> >         return k;
> >     }
> > };
>
> > template<class T,class U>
> > struct innerCast<const T&,U>
> > {
> >     static const T & get(U &k)
> >     {
> >         return k;
> >     }
> > };
>
> > template<class T>
> > struct cast
> > {
> >     typedef typename boost::mpl::at_c<typename T::param_type,0>::type
> > ret_type;
>
> >     static ret_type get(klass &k)
> >     {
> >         return innerCast<ret_type,klass>::get(k);
> >     }
>
> > };
>
> > /////////////////////////////////////////
> > // Below is what would be the user code
> > /////////////////////////////////////////
>
> > struct f
> > {
> >     typedef boost::mpl::vector<double&>::type param_type;
> >     static void call(double &x)
> >     {
> >         cout << " double &x\n";
> >     }
> > };
>
> > struct fc
> > {
> >     typedef boost::mpl::vector<const double&> param_type;
> >     static void call(const double &x)
> >     {
> >         cout << " const double &x\n";
> >     }
> > };
>
> > struct ft
> > {
> >     typedef boost::mpl::vector<double> param_type;
> >     static void call(double x)
> >     {
> >         cout << " double\n";
> >     }
>
> > };
>
> > int main()
> > {
>
> >     try
> >     {
>
> >         double x(3.142);
>
> >         klass k_non_const(x);
> >         klass k_const(3.142);
>
> >         f::call( cast<f>::get(k_non_const) );
> >         fc::call( cast<fc>::get(k_non_const));
> >         ft::call( cast<ft>::get(k_non_const));
>
> >         fc::call( cast<fc>::get(k_const));
> >         ft::call( cast<ft>::get(k_const)); // this one *NO LONGER*
> > throws with gcc
> >     }
> >     catch(const std::exception &err)
> >     {
> >         cout << err.what() << "\n";
> >     }
>
> > }
>
> > ---------------------------------------------
>
> > Maybe some of the class names have alot of scope to be more
> > meaningful :-)
>
> Here is an alternative idea (hopefully, I understood your aim):
>
> #include <iostream>
>
> struct oops {};
>
> template < typename T >
> class const_reference {
>
>   T const * ptr;
>
> public:
>
>   const_reference ( T const & r )
>     : ptr ( &r )
>   {}
>
>   T const & get ( void ) {
>     return ( *ptr );
>   }
>
>   operator T const & ( void ) {
>     return ( *ptr );
>   }
>
> };
>
> template < typename T >
> class reference {
>
>   T * ptr;
>
> public:
>
>   reference ( T & r )
>     : ptr ( &r )
>   {}
>
>   T & get ( void ) {
>     return ( *ptr );
>   }
>
>   operator T & ( void ) {
>     return ( *ptr );
>   }
>
> };
>
> template < typename T >
> class wrapper {
> private:
>
>   T *       the_ptr;
>   T const * the_c_ptr;
>
> public:
>
>   wrapper ( T & ref )
>     : the_ptr ( &ref )
>     , the_c_ptr ()
>   {}
>
>   wrapper ( T const & cref )
>     : the_ptr ()
>     , the_c_ptr ( &cref )
>   {}
>
>   operator reference<T> ( void ) {
>     std::cout << "non-const\n";
>     if ( the_ptr ) {
>       return ( *the_ptr );
>     }
>     throw ( oops() );
>   }
>
>   operator const_reference<T> ( void ) {
>     std::cout << "const\n";
>     if ( the_ptr ) {
>       return ( *the_ptr );
>     }
>     return ( *the_c_ptr );
>   }
>
>   operator T ( void ) {
>     if ( the_ptr ) {
>       return ( *the_ptr );
>     }
>     return ( *the_c_ptr );
>   }
>
> };
>
> double const pi = 3.14159;
> double e = 2.71828;
>
> typedef wrapper< double > klass;
>
> void foo_ref ( reference<double> ) {
>   std::cout << "reference\n";
>
> }
>
> void foo_cref ( const_reference<double> ) {
>   std::cout << "const reference\n";
>
> }
>
> void foo_val ( double ) {
>   std::cout << "value\n";
>
> }
>
> int main ( void ) {
>   klass rw ( e );
>   klass ro ( pi );
>   foo_val( rw );
>   foo_cref( rw );
>   foo_ref( rw );
>   foo_val( ro );
>   foo_cref( ro );
>   foo_ref( ro );
>
> }
>
> Best,
>
> Kai-Uwe Bux


In my case the functions foo_ref, foo_cref, foo_val will be given (by
the client) and may ( and most probably will)  be compiled without any
knowledge of the types reference and const_reference. So I would need
it to work with :

--------------------------
void foo_ref ( double & ) {
  std::cout << "reference\n";
}

void foo_cref ( const double & ) {
  std::cout << "const reference\n";
}

void foo_val ( double  ) {
  std::cout << "value\n";
}
--------------------------

(In fact to be even more precise, in my real scenario they will be
class constructors.)
When I compile your code with above modifications I get the
compilation error:

-------------------------------------------------
main/main.cpp: In function 'int main()':
main/main.cpp:93:15: error: invalid initialization of reference of
type 'double&
' from expression of type 'klass'
main/main.cpp:72:6: error: in passing argument 1 of 'void
foo_ref(double&)'
main/main.cpp:96:15: error: invalid initialization of reference of
type 'double&
' from expression of type 'klass'
main/main.cpp:72:6: error: in passing argument 1 of 'void
foo_ref(double&)'
------------------------------------------------

Best
N

[toc] | [prev] | [next] | [standalone]


#7692

FromNarinder <narinder.claire@gmail.com>
Date2011-07-09 22:01 -0700
Message-ID<6def1a38-0e27-4b1d-b3cc-9d8231b08569@t9g2000vbv.googlegroups.com>
In reply to#7691
On Jul 10, 5:39 am, Narinder <narinder.cla...@gmail.com> wrote:
> On Jul 10, 12:15 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>
>
>
>
>
>
>
>
>
> > Narinder wrote:
> > > On Jul 9, 12:34 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> > >> Narinder wrote:
> > >> >>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> > >> >>At the moment, I don't see why.
>
> > >> > That is indeed curious.
> > >> > However on my issue, I think I am expecting something from C++ .. when
> > >> > I obviously should know better,  "C++ (101): C++ doesn't dispatch on
> > >> > the return type".
>
> > >> That, I think, is not the entire picture. There is clause [14.8.2.3] that
> > >> deals with deducing template arguments for templated conversion
> > >> operators. Here, the result type desired by the conversion is taken into
> > >> account. Howerver, reading that clause, I find it hard to tell whether
> > >> the deduction should fail because of ambiguity, whether the const version
> > >> should be instantiated, or whether the non-const version should be
> > >> chosen.
>
> > >> > My question stems from wanting to pass parameters to a function via an
> > >> > intermediary which holds references to the values to be passed. And
> > >> > this would be done at runtime.
>
> > >> > Given :
>
> > >> > void f( double x);
>
> > >> > I want to be able to do:
>
> > >> > const double x=3.142;
> > >> > intermediary v = x; // so v will hold a
> > >> > std::tr1::reference_wrapper<const double>
> > >> > f(v);               // I suspect gcc will complain because v is unable
> > >> > to give up its const ref
> > >> > // but as we have seen gcc calls operator
> > >> > double&()
>
> > >> Hm, the following compiles:
>
> > >> #include <iostream>
>
> > >> void foo ( double arg ) {
> > >> std::cout << arg << "\n";
>
> > >> }
>
> > >> template < typename T >
> > >> class reference_wrapper {
>
> > >> T* the_ptr;
>
> > >> public:
>
> > >> typedef T type;
> > >> typedef T& reference;
>
> > >> reference_wrapper ( reference t_ref )
> > >> : the_ptr ( &t_ref )
> > >> {}
>
> > >> operator reference ( void ) {
> > >> return ( *the_ptr );
> > >> }
>
> > >> reference get ( void ) {
> > >> return ( *the_ptr );
> > >> }
>
> > >> };
>
> > >> int main ( void ) {
> > >> double const pi = 3.14159;
> > >> reference_wrapper< double const > x = pi;
> > >> foo( x );
>
> > >> }
> > >> > My way around this will be to have the user provide a precise boost
> > >> > typelist embodying the function signature:
>
> > >> > boost::mpl::vector<double>
>
> > >> > and use this to dispatch correctly.
>
> > >> Huh?
>
> > >> Best,
>
> > >> Kai-Uwe Bux
>
> > > Consider the following functions:
>
> > > f_ref(double&)              // may be a member function that keeps the
> > > rw ref
> > > f_const_ref(const double&)  // maybe a memeber function that keeps the
> > > ro ref
> > > f_val(double)               // expects the value byval
>
> > > you have one 'variant'
>
> > > variant v = 3.142;
>
> > > double x=3.142;
> > > variant v2 = x;
>
> > > const double xx=3.142
> > > variant v3 = 3.142
>
> > > I want to deliver (since it doesn't have to be done by casting) v2 to
> > > f_ref, but not v & v3
> > > I want to deliver v2 & v3 to f_const_ref but not v
> > > and i want to be able to deliver all of them to f_val
>
> > > Moreover my variants will be initialised at runtime.
>
> > > I have sketched (but compiles and executes ) what I think is a
> > > solution.
> > > (I have used boost::mpl::vector to be able to generalise to more than
> > > one parameter)
>
> > > -------------------------------
> > > #include<iostream>
> > > #include<boost/ref.hpp>
> > > #include<boost/variant.hpp>
> > > #include<boost/mpl/vector.hpp>
> > > #include<boost/mpl/at.hpp>
>
> > > using namespace std;
>
> > > double pi = 3.142;
> > > typedef boost::reference_wrapper<double>  ref;
> > > typedef boost::reference_wrapper<const double>  const_ref;
>
> > > struct klass
> > > {
> > >     klass(double & x):innerVariant(boost::ref(x)){}
> > >     klass(const double & x):innerVariant(boost::cref(x)){}
>
> > >     template<class T>
> > >     operator T& ()
> > >     {
> > >         cout << " ... casting to double&  ";
> > >         return boost::get<ref>(innerVariant);
> > >     }
>
> > >     template<class T>
> > >     operator const T&()
> > >     {
> > >         cout << " ... casting to const double&  ";
> > >         if(boost::get<ref>(&innerVariant))
> > >         {
> > >             return boost::get<ref>(innerVariant);
> > >         }
> > >         return boost::get<const_ref>(innerVariant);
>
> > >     }
>
> > >     const double &get_by_val()
> > >     {
> > >         return (const double&)(*this);
> > >     }
>
> > > private:
> > >     boost::variant<ref,const_ref >  innerVariant;
> > > };
>
> > > template<class T,class U>
> > > struct innerCast
> > > {
> > >     static const T & get(U &k)
> > >     {
> > >         return k.get_by_val();
> > >     }
> > > };
>
> > > template<class T,class U>
> > > struct innerCast<T&,U>
> > > {
> > >     static T & get(U &k)
> > >     {
> > >         return k;
> > >     }
> > > };
>
> > > template<class T,class U>
> > > struct innerCast<const T&,U>
> > > {
> > >     static const T & get(U &k)
> > >     {
> > >         return k;
> > >     }
> > > };
>
> > > template<class T>
> > > struct cast
> > > {
> > >     typedef typename boost::mpl::at_c<typename T::param_type,0>::type
> > > ret_type;
>
> > >     static ret_type get(klass &k)
> > >     {
> > >         return innerCast<ret_type,klass>::get(k);
> > >     }
>
> > > };
>
> > > /////////////////////////////////////////
> > > // Below is what would be the user code
> > > /////////////////////////////////////////
>
> > > struct f
> > > {
> > >     typedef boost::mpl::vector<double&>::type param_type;
> > >     static void call(double &x)
> > >     {
> > >         cout << " double &x\n";
> > >     }
> > > };
>
> > > struct fc
> > > {
> > >     typedef boost::mpl::vector<const double&> param_type;
> > >     static void call(const double &x)
> > >     {
> > >         cout << " const double &x\n";
> > >     }
> > > };
>
> > > struct ft
> > > {
> > >     typedef boost::mpl::vector<double> param_type;
> > >     static void call(double x)
> > >     {
> > >         cout << " double\n";
> > >     }
>
> > > };
>
> > > int main()
> > > {
>
> > >     try
> > >     {
>
> > >         double x(3.142);
>
> > >         klass k_non_const(x);
> > >         klass k_const(3.142);
>
> > >         f::call( cast<f>::get(k_non_const) );
> > >         fc::call( cast<fc>::get(k_non_const));
> > >         ft::call( cast<ft>::get(k_non_const));
>
> > >         fc::call( cast<fc>::get(k_const));
> > >         ft::call( cast<ft>::get(k_const)); // this one *NO LONGER*
> > > throws with gcc
> > >     }
> > >     catch(const std::exception &err)
> > >     {
> > >         cout << err.what() << "\n";
> > >     }
>
> > > }
>
> > > ---------------------------------------------
>
> > > Maybe some of the class names have alot of scope to be more
> > > meaningful :-)
>
> > Here is an alternative idea (hopefully, I understood your aim):
>
> > #include <iostream>
>
> > struct oops {};
>
> > template < typename T >
> > class const_reference {
>
> >   T const * ptr;
>
> > public:
>
> >   const_reference ( T const & r )
> >     : ptr ( &r )
> >   {}
>
> >   T const & get ( void ) {
> >     return ( *ptr );
> >   }
>
> >   operator T const & ( void ) {
> >     return ( *ptr );
> >   }
>
> > };
>
> > template < typename T >
> > class reference {
>
> >   T * ptr;
>
> > public:
>
> >   reference ( T & r )
> >     : ptr ( &r )
> >   {}
>
> >   T & get ( void ) {
> >     return ( *ptr );
> >   }
>
> >   operator T & ( void ) {
> >     return ( *ptr );
> >   }
>
> > };
>
> > template < typename T >
> > class wrapper {
> > private:
>
> >   T *       the_ptr;
> >   T const * the_c_ptr;
>
> > public:
>
> >   wrapper ( T & ref )
> >     : the_ptr ( &ref )
> >     , the_c_ptr ()
> >   {}
>
> >   wrapper ( T const & cref )
> >     : the_ptr ()
> >     , the_c_ptr ( &cref )
> >   {}
>
> >   operator reference<T> ( void ) {
> >     std::cout << "non-const\n";
> >     if ( the_ptr ) {
> >       return ( *the_ptr );
> >     }
> >     throw ( oops() );
> >   }
>
> >   operator const_reference<T> ( void ) {
> >     std::cout << "const\n";
> >     if ( the_ptr ) {
> >       return ( *the_ptr );
> >     }
> >     return ( *the_c_ptr );
> >   }
>
> >   operator T ( void ) {
> >     if ( the_ptr ) {
> >       return ( *the_ptr );
> >     }
> >     return ( *the_c_ptr );
> >   }
>
> > };
>
> > double const pi = 3.14159;
> > double e = 2.71828;
>
> > typedef wrapper< double > klass;
>
> > void foo_ref ( reference<double> ) {
> >   std::cout << "reference\n";
>
> > }
>
> > void foo_cref ( const_reference<double> ) {
> >   std::cout << "const reference\n";
>
> > }
>
> > void foo_val ( double ) {
> >   std::cout << "value\n";
>
> > }
>
> > int main ( void ) {
> >   klass rw ( e );
> >   klass ro ( pi );
> >   foo_val( rw );
> >   foo_cref( rw );
> >   foo_ref( rw );
> >   foo_val( ro );
> >   foo_cref( ro );
> >   foo_ref( ro );
>
> > }
>
> > Best,
>
> > Kai-Uwe Bux
>
> In my case the functions foo_ref, foo_cref, foo_val will be given (by
> the client) and may ( and most probably will)  be compiled without any
> knowledge of the types reference and const_reference. So I would need
> it to work with :
>
> --------------------------
> void foo_ref ( double & ) {
>   std::cout << "reference\n";
>
> }
>
> void foo_cref ( const double & ) {
>   std::cout << "const reference\n";
>
> }
>
> void foo_val ( double  ) {
>   std::cout << "value\n";}
>
> --------------------------
>
> (In fact to be even more precise, in my real scenario they will be
> class constructors.)
> When I compile your code with above modifications I get the
> compilation error:
>
> -------------------------------------------------
> main/main.cpp: In function 'int main()':
> main/main.cpp:93:15: error: invalid initialization of reference of
> type 'double&
> ' from expression of type 'klass'
> main/main.cpp:72:6: error: in passing argument 1 of 'void
> foo_ref(double&)'
> main/main.cpp:96:15: error: invalid initialization of reference of
> type 'double&
> ' from expression of type 'klass'
> main/main.cpp:72:6: error: in passing argument 1 of 'void
> foo_ref(double&)'
> ------------------------------------------------
>
> Best
> N

..also if I make the following amendments :

------------------------------------

....
struct someClass
{
	someClass(const double &x_):x(x_){}
	void show()const{std::cout << "x=" <<x <<"\n";}
	const double &x;
};

int main ( void ) {

  double const pi = 3.14159;
  double e = 2.71828;

  klass rw ( e );
  klass ro ( pi );
  foo_val( rw );
  foo_cref( rw );
 // foo_ref( rw );
  foo_val( ro );
  foo_cref( ro );
 // foo_ref( ro );

  someClass s(rw);
  s.show();
  e=0.0;
  s.show();
}

-------------------------

It doesn't work as expected, specifically the last s.show() display 0.

Best N

[toc] | [prev] | [next] | [standalone]


#7698

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-07-10 13:43 +0200
Message-ID<ivc3a0$t5j$1@hoshi.visyn.net>
In reply to#7692
Narinder wrote:

> On Jul 10, 5:39 am, Narinder <narinder.cla...@gmail.com> wrote:
>> On Jul 10, 12:15 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> > Narinder wrote:
>> > > On Jul 9, 12:34 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>> > >> Narinder wrote:
>> > >> >>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>> > >> >>At the moment, I don't see why.
>>
>> > >> > That is indeed curious.
>> > >> > However on my issue, I think I am expecting something from C++ ..
>> > >> > when I obviously should know better,  "C++ (101): C++ doesn't
>> > >> > dispatch on the return type".
>>
>> > >> That, I think, is not the entire picture. There is clause [14.8.2.3]
>> > >> that deals with deducing template arguments for templated conversion
>> > >> operators. Here, the result type desired by the conversion is taken
>> > >> into account. Howerver, reading that clause, I find it hard to tell
>> > >> whether the deduction should fail because of ambiguity, whether the
>> > >> const version should be instantiated, or whether the non-const
>> > >> version should be chosen.
>>
>> > >> > My question stems from wanting to pass parameters to a function
>> > >> > via an intermediary which holds references to the values to be
>> > >> > passed. And this would be done at runtime.
>>
>> > >> > Given :
>>
>> > >> > void f( double x);
>>
>> > >> > I want to be able to do:
>>
>> > >> > const double x=3.142;
>> > >> > intermediary v = x; // so v will hold a
>> > >> > std::tr1::reference_wrapper<const double>
>> > >> > f(v);               // I suspect gcc will complain because v is
>> > >> > unable to give up its const ref
>> > >> > // but as we have seen gcc calls operator
>> > >> > double&()
>>
>> > >> Hm, the following compiles:
>>
>> > >> #include <iostream>
>>
>> > >> void foo ( double arg ) {
>> > >> std::cout << arg << "\n";
>>
>> > >> }
>>
>> > >> template < typename T >
>> > >> class reference_wrapper {
>>
>> > >> T* the_ptr;
>>
>> > >> public:
>>
>> > >> typedef T type;
>> > >> typedef T& reference;
>>
>> > >> reference_wrapper ( reference t_ref )
>> > >> : the_ptr ( &t_ref )
>> > >> {}
>>
>> > >> operator reference ( void ) {
>> > >> return ( *the_ptr );
>> > >> }
>>
>> > >> reference get ( void ) {
>> > >> return ( *the_ptr );
>> > >> }
>>
>> > >> };
>>
>> > >> int main ( void ) {
>> > >> double const pi = 3.14159;
>> > >> reference_wrapper< double const > x = pi;
>> > >> foo( x );
>>
>> > >> }
>> > >> > My way around this will be to have the user provide a precise
>> > >> > boost typelist embodying the function signature:
>>
>> > >> > boost::mpl::vector<double>
>>
>> > >> > and use this to dispatch correctly.
>>
>> > >> Huh?
>>
>> > >> Best,
>>
>> > >> Kai-Uwe Bux
>>
>> > > Consider the following functions:
>>
>> > > f_ref(double&)              // may be a member function that keeps
>> > > the rw ref
>> > > f_const_ref(const double&)  // maybe a memeber function that keeps
>> > > the ro ref
>> > > f_val(double)               // expects the value byval
>>
>> > > you have one 'variant'
>>
>> > > variant v = 3.142;
>>
>> > > double x=3.142;
>> > > variant v2 = x;
>>
>> > > const double xx=3.142
>> > > variant v3 = 3.142
>>
>> > > I want to deliver (since it doesn't have to be done by casting) v2 to
>> > > f_ref, but not v & v3
>> > > I want to deliver v2 & v3 to f_const_ref but not v
>> > > and i want to be able to deliver all of them to f_val
>>
>> > > Moreover my variants will be initialised at runtime.
>>
>> > > I have sketched (but compiles and executes ) what I think is a
>> > > solution.
>> > > (I have used boost::mpl::vector to be able to generalise to more than
>> > > one parameter)
>>
>> > > -------------------------------
>> > > #include<iostream>
>> > > #include<boost/ref.hpp>
>> > > #include<boost/variant.hpp>
>> > > #include<boost/mpl/vector.hpp>
>> > > #include<boost/mpl/at.hpp>
>>
>> > > using namespace std;
>>
>> > > double pi = 3.142;
>> > > typedef boost::reference_wrapper<double>  ref;
>> > > typedef boost::reference_wrapper<const double>  const_ref;
>>
>> > > struct klass
>> > > {
>> > > klass(double & x):innerVariant(boost::ref(x)){}
>> > > klass(const double & x):innerVariant(boost::cref(x)){}
>>
>> > > template<class T>
>> > > operator T& ()
>> > > {
>> > > cout << " ... casting to double&  ";
>> > > return boost::get<ref>(innerVariant);
>> > > }
>>
>> > > template<class T>
>> > > operator const T&()
>> > > {
>> > > cout << " ... casting to const double&  ";
>> > > if(boost::get<ref>(&innerVariant))
>> > > {
>> > > return boost::get<ref>(innerVariant);
>> > > }
>> > > return boost::get<const_ref>(innerVariant);
>>
>> > > }
>>
>> > > const double &get_by_val()
>> > > {
>> > > return (const double&)(*this);
>> > > }
>>
>> > > private:
>> > > boost::variant<ref,const_ref >  innerVariant;
>> > > };
>>
>> > > template<class T,class U>
>> > > struct innerCast
>> > > {
>> > > static const T & get(U &k)
>> > > {
>> > > return k.get_by_val();
>> > > }
>> > > };
>>
>> > > template<class T,class U>
>> > > struct innerCast<T&,U>
>> > > {
>> > > static T & get(U &k)
>> > > {
>> > > return k;
>> > > }
>> > > };
>>
>> > > template<class T,class U>
>> > > struct innerCast<const T&,U>
>> > > {
>> > > static const T & get(U &k)
>> > > {
>> > > return k;
>> > > }
>> > > };
>>
>> > > template<class T>
>> > > struct cast
>> > > {
>> > > typedef typename boost::mpl::at_c<typename T::param_type,0>::type
>> > > ret_type;
>>
>> > > static ret_type get(klass &k)
>> > > {
>> > > return innerCast<ret_type,klass>::get(k);
>> > > }
>>
>> > > };
>>
>> > > /////////////////////////////////////////
>> > > // Below is what would be the user code
>> > > /////////////////////////////////////////
>>
>> > > struct f
>> > > {
>> > > typedef boost::mpl::vector<double&>::type param_type;
>> > > static void call(double &x)
>> > > {
>> > > cout << " double &x\n";
>> > > }
>> > > };
>>
>> > > struct fc
>> > > {
>> > > typedef boost::mpl::vector<const double&> param_type;
>> > > static void call(const double &x)
>> > > {
>> > > cout << " const double &x\n";
>> > > }
>> > > };
>>
>> > > struct ft
>> > > {
>> > > typedef boost::mpl::vector<double> param_type;
>> > > static void call(double x)
>> > > {
>> > > cout << " double\n";
>> > > }
>>
>> > > };
>>
>> > > int main()
>> > > {
>>
>> > > try
>> > > {
>>
>> > > double x(3.142);
>>
>> > > klass k_non_const(x);
>> > > klass k_const(3.142);
>>
>> > > f::call( cast<f>::get(k_non_const) );
>> > > fc::call( cast<fc>::get(k_non_const));
>> > > ft::call( cast<ft>::get(k_non_const));
>>
>> > > fc::call( cast<fc>::get(k_const));
>> > > ft::call( cast<ft>::get(k_const)); // this one *NO LONGER*
>> > > throws with gcc
>> > > }
>> > > catch(const std::exception &err)
>> > > {
>> > > cout << err.what() << "\n";
>> > > }
>>
>> > > }
>>
>> > > ---------------------------------------------
>>
>> > > Maybe some of the class names have alot of scope to be more
>> > > meaningful :-)
>>
>> > Here is an alternative idea (hopefully, I understood your aim):
>>
>> > #include <iostream>
>>
>> > struct oops {};
>>
>> > template < typename T >
>> > class const_reference {
>>
>> > T const * ptr;
>>
>> > public:
>>
>> > const_reference ( T const & r )
>> > : ptr ( &r )
>> > {}
>>
>> > T const & get ( void ) {
>> > return ( *ptr );
>> > }
>>
>> > operator T const & ( void ) {
>> > return ( *ptr );
>> > }
>>
>> > };
>>
>> > template < typename T >
>> > class reference {
>>
>> > T * ptr;
>>
>> > public:
>>
>> > reference ( T & r )
>> > : ptr ( &r )
>> > {}
>>
>> > T & get ( void ) {
>> > return ( *ptr );
>> > }
>>
>> > operator T & ( void ) {
>> > return ( *ptr );
>> > }
>>
>> > };
>>
>> > template < typename T >
>> > class wrapper {
>> > private:
>>
>> > T *       the_ptr;
>> > T const * the_c_ptr;
>>
>> > public:
>>
>> > wrapper ( T & ref )
>> > : the_ptr ( &ref )
>> > , the_c_ptr ()
>> > {}
>>
>> > wrapper ( T const & cref )
>> > : the_ptr ()
>> > , the_c_ptr ( &cref )
>> > {}
>>
>> > operator reference<T> ( void ) {
>> > std::cout << "non-const\n";
>> > if ( the_ptr ) {
>> > return ( *the_ptr );
>> > }
>> > throw ( oops() );
>> > }
>>
>> > operator const_reference<T> ( void ) {
>> > std::cout << "const\n";
>> > if ( the_ptr ) {
>> > return ( *the_ptr );
>> > }
>> > return ( *the_c_ptr );
>> > }
>>
>> > operator T ( void ) {
>> > if ( the_ptr ) {
>> > return ( *the_ptr );
>> > }
>> > return ( *the_c_ptr );
>> > }
>>
>> > };
>>
>> > double const pi = 3.14159;
>> > double e = 2.71828;
>>
>> > typedef wrapper< double > klass;
>>
>> > void foo_ref ( reference<double> ) {
>> > std::cout << "reference\n";
>>
>> > }
>>
>> > void foo_cref ( const_reference<double> ) {
>> > std::cout << "const reference\n";
>>
>> > }
>>
>> > void foo_val ( double ) {
>> > std::cout << "value\n";
>>
>> > }
>>
>> > int main ( void ) {
>> > klass rw ( e );
>> > klass ro ( pi );
>> > foo_val( rw );
>> > foo_cref( rw );
>> > foo_ref( rw );
>> > foo_val( ro );
>> > foo_cref( ro );
>> > foo_ref( ro );
>>
>> > }
>>
>> > Best,
>>
>> > Kai-Uwe Bux
>>
>> In my case the functions foo_ref, foo_cref, foo_val will be given (by
>> the client) and may ( and most probably will)  be compiled without any
>> knowledge of the types reference and const_reference. So I would need
>> it to work with :
>>
>> --------------------------
>> void foo_ref ( double & ) {
>> std::cout << "reference\n";
>>
>> }
>>
>> void foo_cref ( const double & ) {
>> std::cout << "const reference\n";
>>
>> }
>>
>> void foo_val ( double  ) {
>> std::cout << "value\n";}
>>
>> --------------------------
>>
>> (In fact to be even more precise, in my real scenario they will be
>> class constructors.)
>> When I compile your code with above modifications I get the
>> compilation error:
>>
>> -------------------------------------------------
>> main/main.cpp: In function 'int main()':
>> main/main.cpp:93:15: error: invalid initialization of reference of
>> type 'double&
>> ' from expression of type 'klass'
>> main/main.cpp:72:6: error: in passing argument 1 of 'void
>> foo_ref(double&)'
>> main/main.cpp:96:15: error: invalid initialization of reference of
>> type 'double&
>> ' from expression of type 'klass'
>> main/main.cpp:72:6: error: in passing argument 1 of 'void
>> foo_ref(double&)'
>> ------------------------------------------------
>>
>> Best
>> N
> 
> ..also if I make the following amendments :
> 
> ------------------------------------
> 
> ....
> struct someClass
> {
> someClass(const double &x_):x(x_){}
> void show()const{std::cout << "x=" <<x <<"\n";}
> const double &x;
> };
> 
> int main ( void ) {
> 
>   double const pi = 3.14159;
>   double e = 2.71828;
> 
>   klass rw ( e );
>   klass ro ( pi );
>   foo_val( rw );
>   foo_cref( rw );
>  // foo_ref( rw );
>   foo_val( ro );
>   foo_cref( ro );
>  // foo_ref( ro );
> 
>   someClass s(rw);
>   s.show();
>   e=0.0;
>   s.show();
> }
> 
> -------------------------
> 
> It doesn't work as expected, specifically the last s.show() display 0.

Hm, what about:

#include <iostream>

struct oops {};

template < typename T >
class const_reference {

  T const * ptr;
  
public:

  const_reference ( T const & r )
    : ptr ( &r )
  {}
  
  T const & get ( void ) {
    return ( *ptr );
  }

  operator T const & ( void ) {
    return ( *ptr );
  }
  
};

template < typename T >
class reference {

  T * ptr;
  
public:

  reference ( T & r )
    : ptr ( &r )
  {}
  
  T & get ( void ) {
    return ( *ptr );
  }

  operator T & ( void ) {
    return ( *ptr );
  }
  
};

template < typename T >
class wrapper {
private:

  T *       the_ptr;
  T const * the_c_ptr;
  
public:
  
  wrapper ( T & ref )
    : the_ptr ( &ref )
    , the_c_ptr ()
  {}

  wrapper ( T const & cref )
    : the_ptr ()
    , the_c_ptr ( &cref )
  {}
  
  operator reference<T> ( void ) {
    std::cout << "convert to non-const reference\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    throw ( oops() );
  }

  operator const_reference<T> ( void ) {
    std::cout << "convert to const reference\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    return ( *the_c_ptr );
  }

  operator T ( void ) {
    std::cout << "convert to value\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    return ( *the_c_ptr );
  }
  
};


template < typename T >
T & convert_to_ref ( reference<T> r ) {
  return ( r );
}

template < typename T >
T const & convert_to_cref ( const_reference<T> r ) {
  return ( r );
}


template < typename T >
struct call_helper_ref {

  void (&f) ( T & );
  
  call_helper_ref ( void (&fct) ( T & ) )
    : f ( fct )
  {}

  void operator() ( reference<T> arg ) const {
    f( arg );
  }

};

template < typename T >
struct call_helper_cref {

  void (&f) ( T const & );
  
  call_helper_cref ( void (&fct) ( T const & ) )
    : f ( fct )
  {}

  void operator() ( const_reference<T> arg ) const {
    f( arg );
  }

};

template < typename T >
struct call_helper_value {

  void (&f) ( T );
  
  call_helper_value ( void (&fct) ( T ) )
    : f ( fct )
  {}

  void operator() ( T arg ) const {
    f( arg );
  }

};

template < typename T >
call_helper_ref< T > call ( void (&f) ( T & ) ) {
  return ( call_helper_ref<T>(f) );
}

template < typename T >
call_helper_cref< T > call ( void (&f) ( T const & ) ) {
  return ( call_helper_cref<T>(f) );
}

template < typename T >
call_helper_value< T > call ( void (&f) ( T ) ) {
  return ( call_helper_value<T>(f) );
}


template < typename C, typename T >
struct is_constructible {

  struct yes_type { char d; };
  struct no_type { yes_type a; yes_type b; };
  
  static
  T & ref ( void );

  static
  T const & cref ( void );

  static
  yes_type check ( C );

  static
  no_type check ( ... );

  static
  bool const from_ref =
    sizeof( check( ref() ) ) == sizeof( yes_type );
  
  static
  bool const from_cref =
    sizeof( check( cref() ) ) == sizeof( yes_type );
  
};

template < typename C, typename T,
	   bool from_non_const = is_constructible<C,T>::from_ref >
struct construct_helper;

template < typename C, typename T >
struct construct_helper<C,T,true> {
  static
  C eval ( wrapper<T> w ) {
    return ( C( convert_to_ref<T>( w ) ) );
  }
};

template < typename C, typename T >
struct construct_helper<C,T,false> {
  static
  C eval ( wrapper<T> w ) {
    return ( C( convert_to_cref<T>( w ) ) );
  }
};

template < typename C, typename T >
C construct_from_wrapper ( wrapper<T> w ) {
  return ( construct_helper<C,T>::eval( w ) );
}


// client code
// ===========

double const pi = 3.14159;
double e = 2.71828;

typedef wrapper< double > klass;


void foo_ref ( double & ) {
  std::cout << "reference\n";
}

void foo_cref ( double const & ) {
  std::cout << "const reference\n";
}

void foo_val ( double ) {
  std::cout << "value\n";
}

struct show {

  double & the_ref;

  show ( double & r )
    : the_ref ( r )
  {}

};


int main ( void ) {
  klass rw ( e );
  klass ro ( pi );
  call(foo_val)( rw );
  call(foo_cref)( rw );
  call(foo_ref)( rw );
  call(foo_val)( ro );
  call(foo_cref)( ro );
  //call(foo_ref)( ro );
  show e_show = construct_from_wrapper<show>( rw );
  std::cout << e_show.the_ref << "\n";
  e = 2;
  std::cout << e_show.the_ref << "\n";
  e_show.the_ref = 1;
  std::cout << e << "\n";
}

This does a gratuitous copy-construction. Maybe in C++0X, one can use move 
or something.


Best,

Kai-Uwe Bux

[toc] | [prev] | [next] | [standalone]


#7699

FromNarinder <narinder.claire@gmail.com>
Date2011-07-10 05:55 -0700
Message-ID<5ce25d38-c7ca-4d4f-9d25-47fc9d6a1ab0@b2g2000vbo.googlegroups.com>
In reply to#7698
On Jul 10, 12:43 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Narinder wrote:
> > On Jul 10, 5:39 am, Narinder <narinder.cla...@gmail.com> wrote:
> >> On Jul 10, 12:15 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>
> >> > Narinder wrote:
> >> > > On Jul 9, 12:34 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> >> > >> Narinder wrote:
> >> > >> >>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> >> > >> >>At the moment, I don't see why.
>
> >> > >> > That is indeed curious.
> >> > >> > However on my issue, I think I am expecting something from C++ ..
> >> > >> > when I obviously should know better,  "C++ (101): C++ doesn't
> >> > >> > dispatch on the return type".
>
> >> > >> That, I think, is not the entire picture. There is clause [14.8.2.3]
> >> > >> that deals with deducing template arguments for templated conversion
> >> > >> operators. Here, the result type desired by the conversion is taken
> >> > >> into account. Howerver, reading that clause, I find it hard to tell
> >> > >> whether the deduction should fail because of ambiguity, whether the
> >> > >> const version should be instantiated, or whether the non-const
> >> > >> version should be chosen.
>
> >> > >> > My question stems from wanting to pass parameters to a function
> >> > >> > via an intermediary which holds references to the values to be
> >> > >> > passed. And this would be done at runtime.
>
> >> > >> > Given :
>
> >> > >> > void f( double x);
>
> >> > >> > I want to be able to do:
>
> >> > >> > const double x=3.142;
> >> > >> > intermediary v = x; // so v will hold a
> >> > >> > std::tr1::reference_wrapper<const double>
> >> > >> > f(v);               // I suspect gcc will complain because v is
> >> > >> > unable to give up its const ref
> >> > >> > // but as we have seen gcc calls operator
> >> > >> > double&()
>
> >> > >> Hm, the following compiles:
>
> >> > >> #include <iostream>
>
> >> > >> void foo ( double arg ) {
> >> > >> std::cout << arg << "\n";
>
> >> > >> }
>
> >> > >> template < typename T >
> >> > >> class reference_wrapper {
>
> >> > >> T* the_ptr;
>
> >> > >> public:
>
> >> > >> typedef T type;
> >> > >> typedef T& reference;
>
> >> > >> reference_wrapper ( reference t_ref )
> >> > >> : the_ptr ( &t_ref )
> >> > >> {}
>
> >> > >> operator reference ( void ) {
> >> > >> return ( *the_ptr );
> >> > >> }
>
> >> > >> reference get ( void ) {
> >> > >> return ( *the_ptr );
> >> > >> }
>
> >> > >> };
>
> >> > >> int main ( void ) {
> >> > >> double const pi = 3.14159;
> >> > >> reference_wrapper< double const > x = pi;
> >> > >> foo( x );
>
> >> > >> }
> >> > >> > My way around this will be to have the user provide a precise
> >> > >> > boost typelist embodying the function signature:
>
> >> > >> > boost::mpl::vector<double>
>
> >> > >> > and use this to dispatch correctly.
>
> >> > >> Huh?
>
> >> > >> Best,
>
> >> > >> Kai-Uwe Bux
>
> >> > > Consider the following functions:
>
> >> > > f_ref(double&)              // may be a member function that keeps
> >> > > the rw ref
> >> > > f_const_ref(const double&)  // maybe a memeber function that keeps
> >> > > the ro ref
> >> > > f_val(double)               // expects the value byval
>
> >> > > you have one 'variant'
>
> >> > > variant v = 3.142;
>
> >> > > double x=3.142;
> >> > > variant v2 = x;
>
> >> > > const double xx=3.142
> >> > > variant v3 = 3.142
>
> >> > > I want to deliver (since it doesn't have to be done by casting) v2 to
> >> > > f_ref, but not v & v3
> >> > > I want to deliver v2 & v3 to f_const_ref but not v
> >> > > and i want to be able to deliver all of them to f_val
>
> >> > > Moreover my variants will be initialised at runtime.
>
> >> > > I have sketched (but compiles and executes ) what I think is a
> >> > > solution.
> >> > > (I have used boost::mpl::vector to be able to generalise to more than
> >> > > one parameter)
>
> >> > > -------------------------------
> >> > > #include<iostream>
> >> > > #include<boost/ref.hpp>
> >> > > #include<boost/variant.hpp>
> >> > > #include<boost/mpl/vector.hpp>
> >> > > #include<boost/mpl/at.hpp>
>
> >> > > using namespace std;
>
> >> > > double pi = 3.142;
> >> > > typedef boost::reference_wrapper<double>  ref;
> >> > > typedef boost::reference_wrapper<const double>  const_ref;
>
> >> > > struct klass
> >> > > {
> >> > > klass(double & x):innerVariant(boost::ref(x)){}
> >> > > klass(const double & x):innerVariant(boost::cref(x)){}
>
> >> > > template<class T>
> >> > > operator T& ()
> >> > > {
> >> > > cout << " ... casting to double&  ";
> >> > > return boost::get<ref>(innerVariant);
> >> > > }
>
> >> > > template<class T>
> >> > > operator const T&()
> >> > > {
> >> > > cout << " ... casting to const double&  ";
> >> > > if(boost::get<ref>(&innerVariant))
> >> > > {
> >> > > return boost::get<ref>(innerVariant);
> >> > > }
> >> > > return boost::get<const_ref>(innerVariant);
>
> >> > > }
>
> >> > > const double &get_by_val()
> >> > > {
> >> > > return (const double&)(*this);
> >> > > }
>
> >> > > private:
> >> > > boost::variant<ref,const_ref >  innerVariant;
> >> > > };
>
> >> > > template<class T,class U>
> >> > > struct innerCast
> >> > > {
> >> > > static const T & get(U &k)
> >> > > {
> >> > > return k.get_by_val();
> >> > > }
> >> > > };
>
> >> > > template<class T,class U>
> >> > > struct innerCast<T&,U>
> >> > > {
> >> > > static T & get(U &k)
> >> > > {
> >> > > return k;
> >> > > }
> >> > > };
>
> >> > > template<class T,class U>
> >> > > struct innerCast<const T&,U>
> >> > > {
> >> > > static const T & get(U &k)
> >> > > {
> >> > > return k;
> >> > > }
> >> > > };
>
> >> > > template<class T>
> >> > > struct cast
> >> > > {
> >> > > typedef typename boost::mpl::at_c<typename T::param_type,0>::type
> >> > > ret_type;
>
> >> > > static ret_type get(klass &k)
> >> > > {
> >> > > return innerCast<ret_type,klass>::get(k);
> >> > > }
>
> >> > > };
>
> >> > > /////////////////////////////////////////
> >> > > // Below is what would be the user code
> >> > > /////////////////////////////////////////
>
> >> > > struct f
> >> > > {
> >> > > typedef boost::mpl::vector<double&>::type param_type;
> >> > > static void call(double &x)
> >> > > {
> >> > > cout << " double &x\n";
> >> > > }
> >> > > };
>
> >> > > struct fc
> >> > > {
> >> > > typedef boost::mpl::vector<const double&> param_type;
> >> > > static void call(const double &x)
> >> > > {
> >> > > cout << " const double &x\n";
> >> > > }
> >> > > };
>
> >> > > struct ft
> >> > > {
> >> > > typedef boost::mpl::vector<double> param_type;
> >> > > static void call(double x)
> >> > > {
> >> > > cout << " double\n";
> >> > > }
>
> >> > > };
>
> >> > > int main()
> >> > > {
>
> >> > > try
> >> > > {
>
> >> > > double x(3.142);
>
> >> > > klass k_non_const(x);
> >> > > klass k_const(3.142);
>
> >> > > f::call( cast<f>::get(k_non_const) );
> >> > > fc::call( cast<fc>::get(k_non_const));
> >> > > ft::call( cast<ft>::get(k_non_const));
>
> >> > > fc::call( cast<fc>::get(k_const));
> >> > > ft::call( cast<ft>::get(k_const)); // this one *NO LONGER*
> >> > > throws with gcc
> >> > > }
> >> > > catch(const std::exception &err)
> >> > > {
> >> > > cout << err.what() << "\n";
> >> > > }
>
> >> > > }
>
> >> > > ---------------------------------------------
>
> >> > > Maybe some of the class names have alot of scope to be more
> >> > > meaningful :-)
>
> >> > Here is an alternative idea (hopefully, I understood your aim):
>
> >> > #include <iostream>
>
> >> > struct oops {};
>
> >> > template < typename T >
> >> > class const_reference {
>
> >> > T const * ptr;
>
> >> > public:
>
> >> > const_reference ( T const & r )
> >> > : ptr ( &r )
> >> > {}
>
> >> > T const & get ( void ) {
> >> > return ( *ptr );
> >> > }
>
> >> > operator T const & ( void ) {
> >> > return ( *ptr );
> >> > }
>
> >> > };
>
> >> > template < typename T >
> >> > class reference {
>
> >> > T * ptr;
>
> >> > public:
>
> >> > reference ( T & r )
> >> > : ptr ( &r )
> >> > {}
>
> >> > T & get ( void ) {
> >> > return ( *ptr );
> >> > }
>
> >> > operator T & ( void ) {
> >> > return ( *ptr );
> >> > }
>
> >> > };
>
> >> > template < typename T >
> >> > class wrapper {
> >> > private:
>
> >> > T *       the_ptr;
> >> > T const * the_c_ptr;
>
> >> > public:
>
> >> > wrapper ( T & ref )
> >> > : the_ptr ( &ref )
> >> > , the_c_ptr ()
> >> > {}
>
> >> > wrapper ( T const & cref )
> >> > : the_ptr ()
> >> > , the_c_ptr ( &cref )
> >> > {}
>
> >> > operator reference<T> ( void ) {
> >> > std::cout << "non-const\n";
> >> > if ( the_ptr ) {
> >> > return ( *the_ptr );
> >> > }
> >> > throw ( oops() );
> >> > }
>
> >> > operator const_reference<T> ( void ) {
> >> > std::cout << "const\n";
> >> > if ( the_ptr ) {
> >> > return ( *the_ptr );
> >> > }
> >> > return ( *the_c_ptr );
> >> > }
>
> >> > operator T ( void ) {
> >> > if ( the_ptr ) {
> >> > return ( *the_ptr );
> >> > }
> >> > return ( *the_c_ptr );
> >> > }
>
> >> > };
>
> >> > double const pi = 3.14159;
> >> > double e = 2.71828;
>
> >> > typedef wrapper< double > klass;
>
> >> > void foo_ref ( reference<double> ) {
> >> > std::cout << "reference\n";
>
> >> > }
>
> >> > void foo_cref ( const_reference<double> ) {
> >> > std::cout << "const reference\n";
>
> >> > }
>
> >> > void foo_val ( double ) {
> >> > std::cout << "value\n";
>
> >> > }
>
> >> > int main ( void ) {
> >> > klass rw ( e );
> >> > klass ro ( pi );
> >> > foo_val( rw );
> >> > foo_cref( rw );
> >> > foo_ref( rw );
> >> > foo_val( ro );
> >> > foo_cref( ro );
> >> > foo_ref( ro );
>
> >> > }
>
> >> > Best,
>
> >> > Kai-Uwe Bux
>
> >> In my case the functions foo_ref, foo_cref, foo_val will be given (by
> >> the client) and may ( and most probably will)  be compiled without any
> >> knowledge of the types reference and const_reference. So I would need
> >> it to work with :
>
> >> --------------------------
> >> void foo_ref ( double & ) {
> >> std::cout << "reference\n";
>
> >> }
>
> >> void foo_cref ( const double & ) {
> >> std::cout << "const reference\n";
>
> >> }
>
> >> void foo_val ( double  ) {
> >> std::cout << "value\n";}
>
> >> --------------------------
>
> >> (In fact to be even more precise, in my real scenario they will be
> >> class constructors.)
> >> When I compile your code with above modifications I get the
> >> compilation error:
>
> >> -------------------------------------------------
> >> main/main.cpp: In function 'int main()':
> >> main/main.cpp:93:15: error: invalid initialization of reference of
> >> type 'double&
> >> ' from expression of type 'klass'
> >> main/main.cpp:72:6: error: in passing argument 1 of 'void
> >> foo_ref(double&)'
> >> main/main.cpp:96:15: error: invalid initialization of reference of
> >> type 'double&
> >> ' from expression of type 'klass'
> >> main/main.cpp:72:6: error: in passing argument 1 of 'void
> >> foo_ref(double&)'
> >> ------------------------------------------------
>
> >> Best
> >> N
>
> > ..also if I make the following amendments :
>
> > ------------------------------------
>
> > ....
> > struct someClass
> > {
> > someClass(const double &x_):x(x_){}
> > void show()const{std::cout << "x=" <<x <<"\n";}
> > const double &x;
> > };
>
> > int main ( void ) {
>
> >   double const pi = 3.14159;
> >   double e = 2.71828;
>
> >   klass rw ( e );
> >   klass ro ( pi );
> >   foo_val( rw );
> >   foo_cref( rw );
> >  // foo_ref( rw );
> >   foo_val( ro );
> >   foo_cref( ro );
> >  // foo_ref( ro );
>
> >   someClass s(rw);
> >   s.show();
> >   e=0.0;
> >   s.show();
> > }
>
> > -------------------------
>
> > It doesn't work as expected, specifically the last s.show() display 0.
>
> Hm, what about:
>
> #include <iostream>
>
> struct oops {};
>
> template < typename T >
> class const_reference {
>
>   T const * ptr;
>
> public:
>
>   const_reference ( T const & r )
>     : ptr ( &r )
>   {}
>
>   T const & get ( void ) {
>     return ( *ptr );
>   }
>
>   operator T const & ( void ) {
>     return ( *ptr );
>   }
>
> };
>
> template < typename T >
> class reference {
>
>   T * ptr;
>
> public:
>
>   reference ( T & r )
>     : ptr ( &r )
>   {}
>
>   T & get ( void ) {
>     return ( *ptr );
>   }
>
>   operator T & ( void ) {
>     return ( *ptr );
>   }
>
> };
>
> template < typename T >
> class wrapper {
> private:
>
>   T *       the_ptr;
>   T const * the_c_ptr;
>
> public:
>
>   wrapper ( T & ref )
>     : the_ptr ( &ref )
>     , the_c_ptr ()
>   {}
>
>   wrapper ( T const & cref )
>     : the_ptr ()
>     , the_c_ptr ( &cref )
>   {}
>
>   operator reference<T> ( void ) {
>     std::cout << "convert to non-const reference\n";
>     if ( the_ptr ) {
>       return ( *the_ptr );
>     }
>     throw ( oops() );
>   }
>
>   operator const_reference<T> ( void ) {
>     std::cout << "convert to const reference\n";
>     if ( the_ptr ) {
>       return ( *the_ptr );
>     }
>     return ( *the_c_ptr );
>   }
>
>   operator T ( void ) {
>     std::cout << "convert to value\n";
>     if ( the_ptr ) {
>       return ( *the_ptr );
>     }
>     return ( *the_c_ptr );
>   }
>
> };
>
> template < typename T >
> T & convert_to_ref ( reference<T> r ) {
>   return ( r );
>
> }
>
> template < typename T >
> T const & convert_to_cref ( const_reference<T> r ) {
>   return ( r );
>
> }
>
> template < typename T >
> struct call_helper_ref {
>
>   void (&f) ( T & );
>
>   call_helper_ref ( void (&fct) ( T & ) )
>     : f ( fct )
>   {}
>
>   void operator() ( reference<T> arg ) const {
>     f( arg );
>   }
>
> };
>
> template < typename T >
> struct call_helper_cref {
>
>   void (&f) ( T const & );
>
>   call_helper_cref ( void (&fct) ( T const & ) )
>     : f ( fct )
>   {}
>
>   void operator() ( const_reference<T> arg ) const {
>     f( arg );
>   }
>
> };
>
> template < typename T >
> struct call_helper_value {
>
>   void (&f) ( T );
>
>   call_helper_value ( void (&fct) ( T ) )
>     : f ( fct )
>   {}
>
>   void operator() ( T arg ) const {
>     f( arg );
>   }
>
> };
>
> template < typename T >
> call_helper_ref< T > call ( void (&f) ( T & ) ) {
>   return ( call_helper_ref<T>(f) );
>
> }
>
> template < typename T >
> call_helper_cref< T > call ( void (&f) ( T const & ) ) {
>   return ( call_helper_cref<T>(f) );
>
> }
>
> template < typename T >
> call_helper_value< T > call ( void (&f) ( T ) ) {
>   return ( call_helper_value<T>(f) );
>
> }
>
> template < typename C, typename T >
> struct is_constructible {
>
>   struct yes_type { char d; };
>   struct no_type { yes_type a; yes_type b; };
>
>   static
>   T & ref ( void );
>
>   static
>   T const & cref ( void );
>
>   static
>   yes_type check ( C );
>
>   static
>   no_type check ( ... );
>
>   static
>   bool const from_ref =
>     sizeof( check( ref() ) ) == sizeof( yes_type );
>
>   static
>   bool const from_cref =
>     sizeof( check( cref() ) ) == sizeof( yes_type );
>
> };
>
> template < typename C, typename T,
>            bool from_non_const = is_constructible<C,T>::from_ref >
> struct construct_helper;
>
> template < typename C, typename T >
> struct construct_helper<C,T,true> {
>   static
>   C eval ( wrapper<T> w ) {
>     return ( C( convert_to_ref<T>( w ) ) );
>   }
>
> };
>
> template < typename C, typename T >
> struct construct_helper<C,T,false> {
>   static
>   C eval ( wrapper<T> w ) {
>     return ( C( convert_to_cref<T>( w ) ) );
>   }
>
> };
>
> template < typename C, typename T >
> C construct_from_wrapper ( wrapper<T> w ) {
>   return ( construct_helper<C,T>::eval( w ) );
>
> }
>
> // client code
> // ===========
>
> double const pi = 3.14159;
> double e = 2.71828;
>
> typedef wrapper< double > klass;
>
> void foo_ref ( double & ) {
>   std::cout << "reference\n";
>
> }
>
> void foo_cref ( double const & ) {
>   std::cout << "const reference\n";
>
> }
>
> void foo_val ( double ) {
>   std::cout << "value\n";
>
> }
>
> struct show {
>
>   double & the_ref;
>
>   show ( double & r )
>     : the_ref ( r )
>   {}
>
> };
>
> int main ( void ) {
>   klass rw ( e );
>   klass ro ( pi );
>   call(foo_val)( rw );
>   call(foo_cref)( rw );
>   call(foo_ref)( rw );
>   call(foo_val)( ro );
>   call(foo_cref)( ro );
>   //call(foo_ref)( ro );
>   show e_show = construct_from_wrapper<show>( rw );
>   std::cout << e_show.the_ref << "\n";
>   e = 2;
>   std::cout << e_show.the_ref << "\n";
>   e_show.the_ref = 1;
>   std::cout << e << "\n";
>
> }
>
> This does a gratuitous copy-construction. Maybe in C++0X, one can use move
> or something.
>
> Best,
>
> Kai-Uwe Bux


Hi,

You're probably going to think I keep changing the goals posts :-)
I assure you I am not.

The best way to illustrate my objective is to paste a degenerate
working demonstration of a my solution. It's degenerate in that it
still doesn't deal with a variable number of parameters. There are 3
source files. factory.h, main.cpp & pvariant.h . I do now have a
complete solution to my original objective and am more than happy to
forward that to you.
I will now copy and paste the code from you last post and play with
it.

Best Regards
Narinder

factory.h
------------------------------------
#include<typeinfo>
#include<vector>

#include"pvariant.h"

using namespace std;

// Our types

struct abstract
{
    virtual double foo()const=0;
    virtual ~abstract(){}
};
struct concrete: public abstract
{
    virtual double foo()const
    {
        cout << "I am concrete1\n\n";
        return 1.0;
    };
};

struct concrete2 : public abstract
{
    concrete2(){}
    operator double(){return 1.0;}

    virtual double foo()const
    {
        cout << "I am concrete2\n\n";
        return 2.0;
    };
};

// Our Types to be created by the factory

struct klass1
{
    typedef boost::mpl::vector<double&,std::string&> signature;
    klass1(double&x,std::string &s)
    {
        cout << "Constructed klass1\n";
        s = "klass1 killed me ! \n";
    }
    void identify()const
    {
        cout << "I am klass1\n\n";
    }
};

struct klass2
{
    typedef boost::mpl::vector<const std::string&,abstract&>
signature;
    klass2(const std::string &s,abstract& abs):theInterface(abs)
    {
        cout << "Constructed klass2\n";
    }
    void identify()const
    {
        cout << "I am klass2\n";
        cout << "Calling foo in abstract ...";
        theInterface.foo();
    }

    abstract &theInterface;
};
-------------------------------------------


************************************


main.cpp
------------------------------------------



#include<vector>
#include<iostream>
#include<string>

#include"factory.h"


typedef boost::mpl::vector<
                            double,
                            bool,
                            std::string,
                            char,
                            std::vector<double>,
                            abstract
                          >::type variant_type_list;
typedef papa::Variant<variant_type_list> variant ;

template<class T>
T * create(variant p0,variant p1)
{
    typedef typename boost::mpl::at_c<typename T::signature::type,
0>::type type_0;
    typedef typename boost::mpl::at_c<typename T::signature::type,
1>::type type_1;

    return new T(p0.get<type_0>(),p1.get<type_1>());
}



int main()
{
    try
    {
        std::string s("Hello");
        double pi = 3.142;
        klass1 * ptr1 = create<klass1>(pi,s );

        ptr1->identify();
        cout << "s is now : " << s << "\n";


        concrete2 c2;

        klass2 * ptr2 = create<klass2>(s,c2 );
        ptr2->identify();

        concrete c1;

        klass2 * ptr2b = create<klass2>(s,c1 );
        ptr2b->identify();



    }
    catch(const char *err)
    {
        cout << err << "\n";
    }
    catch(const std::exception &err)
    {
        cout << "Exception : "<< err.what() << endl;
    }


    char ch;
    cin >> ch;
    return 0;


}


------------------------------------------------------


************************************


pvariant.h
----------------------------------------------------


#ifndef PVARIANT_H_GUARD
#define PVARIANT_H_GUARD

//#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
//#define BOOST_MPL_LIMIT_VECTOR_SIZE 20

// STD INCLUDES


// TR1 INCLUDES
#include<boost/tr1/type_traits.hpp>

#ifdef _MSC_VER
    #include<boost/ref.hpp>
#else
    #include<boost/tr1/functional.hpp>
#endif


// BOOST INCLUDES
#include<boost/variant.hpp>
    // mpl
#include<boost/mpl/transform.hpp>
#include<boost/mpl/vector.hpp>
#include<boost/mpl/size.hpp>
#include<boost/mpl/filter_view.hpp>
#include<boost/mpl/contains.hpp>
#include<boost/mpl/transform_view.hpp>
#include<boost/mpl/insert_range.hpp>
#include<boost/mpl/assert.hpp>
#include<boost/mpl/at.hpp>


namespace papa
{


#ifdef _MSC_VER
        namespace ref_wrapper_ns = boost;
#else
        namespace ref_wrapper_ns = std::tr1;
#endif

        template<class T>
        ref_wrapper_ns::reference_wrapper<T> ref( T&t)
        {
            return ref_wrapper_ns::ref(t);
        }

        template<class T>
        ref_wrapper_ns::reference_wrapper<const T> cref( const T&t)
        {
            return ref_wrapper_ns::cref(t);
        }
    namespace private_impl
    {

        template<class T>
        struct add_ref_wrapper
        {
            typedef  papa::ref_wrapper_ns::reference_wrapper<T> type;
        };

        template<class T>
        struct add_const_ref_wrapper
        {
            typedef papa::ref_wrapper_ns::reference_wrapper<const T>
type;
        };


        template<int i>
        struct is_1
        {
            static const bool value = false;
        };

        template<>
        struct is_1<1>
        {
            static const bool value = true;
        };

        template<class seq1,class seq2>
        struct concat
        {
            typedef typename boost::mpl::vector0<>::type
empty_vector_type;
            typedef typename
boost::mpl::insert_range<empty_vector_type, typename
boost::mpl::end<empty_vector_type>::type, seq1>::type asvector;
            typedef typename boost::mpl::insert_range<asvector,
typename boost::mpl::end<asvector>::type, seq2 >::type type;

        };
    }

template<class raw_variant_type_list>
class Variant
{


    // The reason we are embedding two variants (const and non_const)
inside
    // innerVariant instead of all the actual types themselves is to
overcome
    // the default size limit of boost::mpl::vector

    struct empty_type
    {
        empty_type(){}
    };

    typedef typename
boost::mpl::transform<raw_variant_type_list,typename
std::tr1::remove_cv<boost::mpl::_1>::type >::type
naked_variant_type_list;
    typedef typename boost::mpl::transform<naked_variant_type_list,
private_impl::add_ref_wrapper<boost::mpl::_1> >::type
ref_variant_type_list;
    typedef typename boost::mpl::transform<naked_variant_type_list,
private_impl::add_const_ref_wrapper<boost::mpl::_1> >::type
const_ref_variant_type_list;

    typedef typename
boost::make_variant_over<ref_variant_type_list>::type ref_variant;
    typedef typename
boost::make_variant_over<const_ref_variant_type_list>::type
const_ref_variant;

    typedef typename
boost::mpl::vector<ref_variant,const_ref_variant>::type
variant_type_list ;
    typedef typename
private_impl::concat<boost::mpl::vector<empty_type> ,variant_type_list>::type
variant_list_with_empty;
    typedef typename
boost::make_variant_over<variant_list_with_empty>::type variant;

    template<class T>
    struct is_recognised_type
    {
        static const bool value =
boost::mpl::contains<naked_variant_type_list,T>::value ||
 
boost::mpl::contains<ref_variant_type_list,T>::value   ||
 
boost::mpl::contains<const_ref_variant_type_list,T>::value  ;
    };

public:

    Variant(){}

    // RECOGNISED ONES

    template<class T>
    Variant(const T&t, const typename boost::enable_if_c<
 
boost::mpl::contains<naked_variant_type_list,T>::value,T>::type * ptr
=0)
               :innerVariant(const_ref_variant(papa::cref<T>(t))){}

    template<class T>
    Variant(T&t, const typename boost::enable_if_c<
 
boost::mpl::contains<naked_variant_type_list,T>::value,T>::type * ptr
=0)
               :innerVariant(ref_variant(papa::ref<T>(t))){}



    template<class T>
    Variant(const T&t, const typename boost::enable_if_c<
 
boost::mpl::contains<ref_variant_type_list,T>::value,T>::type * ptr
=0)
               :innerVariant(ref_variant(t)){}



    template<class T>
    Variant(const T&t, const typename boost::enable_if_c<
 
boost::mpl::contains<const_ref_variant_type_list,T>::value,T>::type *
ptr =0)
               :innerVariant(const_ref_variant(t)){}

    // ONES THAT REQUIRE CASTING


    // Conversions to interfaces

    template<class T>
    Variant(const T&t,
            const typename
boost::disable_if_c<is_recognised_type<T>::value,T >::type * ptr =0,
            const typename boost::disable_if_c<
                    boost::mpl::empty<
                       typename boost::mpl::filter_view<
 
naked_variant_type_list,std::tr1::is_base_of<boost::mpl::_,T>
                            >::type>::value>::type * pt =0)
    {
        typedef typename
boost::mpl::filter_view<naked_variant_type_list,std::tr1::is_base_of<boost::mpl::_,T>
>::type possibilities;

 
BOOST_MPL_ASSERT_MSG(private_impl::is_1<boost::mpl::size<possibilities>::value
>::value, CONSTRUCTOR_OVERLOAD_RESOLUTION_WAS_AMBIGUOUS, (T,
possibilities ) );

        innerVariant = const_ref_variant(papa::cref<typename
boost::mpl::at_c<possibilities,0>::type>(t));
    }


    template<class T>
    Variant(T&t,
            const typename
boost::disable_if_c<is_recognised_type<T>::value,T >::type * ptr =0,
            const typename boost::disable_if_c<
                    boost::mpl::empty<
                       typename boost::mpl::filter_view<
 
naked_variant_type_list,std::tr1::is_base_of<boost::mpl::_,T>
                            >::type>::value>::type * pt =0)
    {
        typedef typename
boost::mpl::filter_view<naked_variant_type_list,std::tr1::is_base_of<boost::mpl::_,T>
>::type possibilities;

 
BOOST_MPL_ASSERT_MSG(private_impl::is_1<boost::mpl::size<possibilities>::value
>::value, CONSTRUCTOR_OVERLOAD_RESOLUTION_WAS_AMBIGUOUS, (T,
possibilities ) );

        innerVariant = ref_variant(papa::ref<typename
boost::mpl::at_c<possibilities,0>::type>(t));
    }



    // Conversions when we can
    template<class T>
    Variant(const T&t,
            const typename
boost::disable_if_c<is_recognised_type<T>::value,T >::type * ptr =0,
            const typename boost::disable_if_c<
                    boost::mpl::empty<
                       typename boost::mpl::filter_view<
 
naked_variant_type_list,boost::is_convertible<T,boost::mpl::_>
                            >::type>::value>::type * pt =0,
            const typename boost::enable_if_c<
                    boost::mpl::empty<
                       typename boost::mpl::filter_view<
 
naked_variant_type_list,std::tr1::is_base_of<boost::mpl::_,T>
                            >::type>::value>::type * pt2 =0)
    {
        typedef typename
boost::mpl::filter_view<raw_variant_type_list,boost::is_convertible<T,boost::mpl::_>
>::type possibilities;

 
BOOST_MPL_ASSERT_MSG(private_impl::is_1<boost::mpl::size<possibilities>::value
>::value, CONSTRUCTOR_OVERLOAD_RESOLUTION_WAS_AMBIGUOUS, (T,
possibilities ) );

        innerVariant = const_ref_variant(papa::cref<typename
boost::mpl::at_c<possibilities,0>::type>(t));
    }


    ///// Ok the what we're really here for

    template<class T>
    T get()
    {
        return innerCast<T>::get(*this);
    }


private:

    template<class T>
    const T& get_by_val()
    {
        // The (const T& in the following is
        // necessary for VS 7.1
        return get_const_ref<T>();
    }


    template<class T>
    struct innerCast
    {
        static const T & get(Variant &v)
        {
            return v.template get_by_val<T>();
        }
    };

    template<class T>
    struct innerCast<T&>
    {
        static T & get(Variant &v)
        {
            return v.template get_non_const_ref<T>();
        }
    };

    template<class T>
    struct innerCast<const T&>
    {
        static const T & get(Variant &v)
        {
            return v.template get_const_ref<T>();
        }
    };

    template<class T>
    T& get_non_const_ref()
    {
        typedef papa::ref_wrapper_ns::reference_wrapper<T> ref_T;

        ref_variant
*theVariant(boost::get<ref_variant>(&innerVariant));
        if(theVariant)
        {
            ref_T * theRef(boost::get<ref_T>(theVariant));
            if(theRef)
            {
                return  *theRef;

            }
            throw ("Wrong Type");
        }
        throw ("Cant cast to const");
    }


    template<class T>
    const T& get_const_ref()
    {
        typedef ref_wrapper_ns::reference_wrapper<T> ref_T;
        typedef ref_wrapper_ns::reference_wrapper<const T>
const_ref_T;

        ref_variant
*theNonConstVariant(boost::get<ref_variant>(&innerVariant));
        if(theNonConstVariant)
        {
            return  get_non_const_ref<T>();
        }

        const_ref_variant
*theVariant(boost::get<const_ref_variant>(&innerVariant));
        if(theVariant)
        {
            const_ref_T * theRef(boost::get<const_ref_T>(theVariant));
            if(theRef)
            {
                return  *theRef;
            }
            throw ("Wrong Type");
        }
        throw ("Cant cast to const");
    }


    variant innerVariant;

};



}

#endif //  PVARIANT_H_GUARD

-------------------------------------------------






[toc] | [prev] | [next] | [standalone]


#7693

FromNarinder <narinder.claire@gmail.com>
Date2011-07-10 00:19 -0700
Message-ID<507038cd-6d10-4473-8f59-71c4c4645cdc@l37g2000yqd.googlegroups.com>
In reply to#7691
On Jul 10, 5:39 am, Narinder <narinder.cla...@gmail.com> wrote:
> On Jul 10, 12:15 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>
>
>
>
>
>
>
>
>
> > Narinder wrote:
> > > On Jul 9, 12:34 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> > >> Narinder wrote:
> > >> >>On Jul 8, 11:06 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> > >> >>At the moment, I don't see why.
>
> > >> > That is indeed curious.
> > >> > However on my issue, I think I am expecting something from C++ .. when
> > >> > I obviously should know better,  "C++ (101): C++ doesn't dispatch on
> > >> > the return type".
>
> > >> That, I think, is not the entire picture. There is clause [14.8.2.3] that
> > >> deals with deducing template arguments for templated conversion
> > >> operators. Here, the result type desired by the conversion is taken into
> > >> account. Howerver, reading that clause, I find it hard to tell whether
> > >> the deduction should fail because of ambiguity, whether the const version
> > >> should be instantiated, or whether the non-const version should be
> > >> chosen.
>
> > >> > My question stems from wanting to pass parameters to a function via an
> > >> > intermediary which holds references to the values to be passed. And
> > >> > this would be done at runtime.
>
> > >> > Given :
>
> > >> > void f( double x);
>
> > >> > I want to be able to do:
>
> > >> > const double x=3.142;
> > >> > intermediary v = x; // so v will hold a
> > >> > std::tr1::reference_wrapper<const double>
> > >> > f(v);               // I suspect gcc will complain because v is unable
> > >> > to give up its const ref
> > >> > // but as we have seen gcc calls operator
> > >> > double&()
>
> > >> Hm, the following compiles:
>
> > >> #include <iostream>
>
> > >> void foo ( double arg ) {
> > >> std::cout << arg << "\n";
>
> > >> }
>
> > >> template < typename T >
> > >> class reference_wrapper {
>
> > >> T* the_ptr;
>
> > >> public:
>
> > >> typedef T type;
> > >> typedef T& reference;
>
> > >> reference_wrapper ( reference t_ref )
> > >> : the_ptr ( &t_ref )
> > >> {}
>
> > >> operator reference ( void ) {
> > >> return ( *the_ptr );
> > >> }
>
> > >> reference get ( void ) {
> > >> return ( *the_ptr );
> > >> }
>
> > >> };
>
> > >> int main ( void ) {
> > >> double const pi = 3.14159;
> > >> reference_wrapper< double const > x = pi;
> > >> foo( x );
>
> > >> }
> > >> > My way around this will be to have the user provide a precise boost
> > >> > typelist embodying the function signature:
>
> > >> > boost::mpl::vector<double>
>
> > >> > and use this to dispatch correctly.
>
> > >> Huh?
>
> > >> Best,
>
> > >> Kai-Uwe Bux
>
> > > Consider the following functions:
>
> > > f_ref(double&)              // may be a member function that keeps the
> > > rw ref
> > > f_const_ref(const double&)  // maybe a memeber function that keeps the
> > > ro ref
> > > f_val(double)               // expects the value byval
>
> > > you have one 'variant'
>
> > > variant v = 3.142;
>
> > > double x=3.142;
> > > variant v2 = x;
>
> > > const double xx=3.142
> > > variant v3 = 3.142
>
> > > I want to deliver (since it doesn't have to be done by casting) v2 to
> > > f_ref, but not v & v3
> > > I want to deliver v2 & v3 to f_const_ref but not v
> > > and i want to be able to deliver all of them to f_val
>
> > > Moreover my variants will be initialised at runtime.
>
> > > I have sketched (but compiles and executes ) what I think is a
> > > solution.
> > > (I have used boost::mpl::vector to be able to generalise to more than
> > > one parameter)
>
> > > -------------------------------
> > > #include<iostream>
> > > #include<boost/ref.hpp>
> > > #include<boost/variant.hpp>
> > > #include<boost/mpl/vector.hpp>
> > > #include<boost/mpl/at.hpp>
>
> > > using namespace std;
>
> > > double pi = 3.142;
> > > typedef boost::reference_wrapper<double>  ref;
> > > typedef boost::reference_wrapper<const double>  const_ref;
>
> > > struct klass
> > > {
> > >     klass(double & x):innerVariant(boost::ref(x)){}
> > >     klass(const double & x):innerVariant(boost::cref(x)){}
>
> > >     template<class T>
> > >     operator T& ()
> > >     {
> > >         cout << " ... casting to double&  ";
> > >         return boost::get<ref>(innerVariant);
> > >     }
>
> > >     template<class T>
> > >     operator const T&()
> > >     {
> > >         cout << " ... casting to const double&  ";
> > >         if(boost::get<ref>(&innerVariant))
> > >         {
> > >             return boost::get<ref>(innerVariant);
> > >         }
> > >         return boost::get<const_ref>(innerVariant);
>
> > >     }
>
> > >     const double &get_by_val()
> > >     {
> > >         return (const double&)(*this);
> > >     }
>
> > > private:
> > >     boost::variant<ref,const_ref >  innerVariant;
> > > };
>
> > > template<class T,class U>
> > > struct innerCast
> > > {
> > >     static const T & get(U &k)
> > >     {
> > >         return k.get_by_val();
> > >     }
> > > };
>
> > > template<class T,class U>
> > > struct innerCast<T&,U>
> > > {
> > >     static T & get(U &k)
> > >     {
> > >         return k;
> > >     }
> > > };
>
> > > template<class T,class U>
> > > struct innerCast<const T&,U>
> > > {
> > >     static const T & get(U &k)
> > >     {
> > >         return k;
> > >     }
> > > };
>
> > > template<class T>
> > > struct cast
> > > {
> > >     typedef typename boost::mpl::at_c<typename T::param_type,0>::type
> > > ret_type;
>
> > >     static ret_type get(klass &k)
> > >     {
> > >         return innerCast<ret_type,klass>::get(k);
> > >     }
>
> > > };
>
> > > /////////////////////////////////////////
> > > // Below is what would be the user code
> > > /////////////////////////////////////////
>
> > > struct f
> > > {
> > >     typedef boost::mpl::vector<double&>::type param_type;
> > >     static void call(double &x)
> > >     {
> > >         cout << " double &x\n";
> > >     }
> > > };
>
> > > struct fc
> > > {
> > >     typedef boost::mpl::vector<const double&> param_type;
> > >     static void call(const double &x)
> > >     {
> > >         cout << " const double &x\n";
> > >     }
> > > };
>
> > > struct ft
> > > {
> > >     typedef boost::mpl::vector<double> param_type;
> > >     static void call(double x)
> > >     {
> > >         cout << " double\n";
> > >     }
>
> > > };
>
> > > int main()
> > > {
>
> > >     try
> > >     {
>
> > >         double x(3.142);
>
> > >         klass k_non_const(x);
> > >         klass k_const(3.142);
>
> > >         f::call( cast<f>::get(k_non_const) );
> > >         fc::call( cast<fc>::get(k_non_const));
> > >         ft::call( cast<ft>::get(k_non_const));
>
> > >         fc::call( cast<fc>::get(k_const));
> > >         ft::call( cast<ft>::get(k_const)); // this one *NO LONGER*
> > > throws with gcc
> > >     }
> > >     catch(const std::exception &err)
> > >     {
> > >         cout << err.what() << "\n";
> > >     }
>
> > > }
>
> > > ---------------------------------------------
>
> > > Maybe some of the class names have alot of scope to be more
> > > meaningful :-)
>
> > Here is an alternative idea (hopefully, I understood your aim):
>
> > #include <iostream>
>
> > struct oops {};
>
> > template < typename T >
> > class const_reference {
>
> >   T const * ptr;
>
> > public:
>
> >   const_reference ( T const & r )
> >     : ptr ( &r )
> >   {}
>
> >   T const & get ( void ) {
> >     return ( *ptr );
> >   }
>
> >   operator T const & ( void ) {
> >     return ( *ptr );
> >   }
>
> > };
>
> > template < typename T >
> > class reference {
>
> >   T * ptr;
>
> > public:
>
> >   reference ( T & r )
> >     : ptr ( &r )
> >   {}
>
> >   T & get ( void ) {
> >     return ( *ptr );
> >   }
>
> >   operator T & ( void ) {
> >     return ( *ptr );
> >   }
>
> > };
>
> > template < typename T >
> > class wrapper {
> > private:
>
> >   T *       the_ptr;
> >   T const * the_c_ptr;
>
> > public:
>
> >   wrapper ( T & ref )
> >     : the_ptr ( &ref )
> >     , the_c_ptr ()
> >   {}
>
> >   wrapper ( T const & cref )
> >     : the_ptr ()
> >     , the_c_ptr ( &cref )
> >   {}
>
> >   operator reference<T> ( void ) {
> >     std::cout << "non-const\n";
> >     if ( the_ptr ) {
> >       return ( *the_ptr );
> >     }
> >     throw ( oops() );
> >   }
>
> >   operator const_reference<T> ( void ) {
> >     std::cout << "const\n";
> >     if ( the_ptr ) {
> >       return ( *the_ptr );
> >     }
> >     return ( *the_c_ptr );
> >   }
>
> >   operator T ( void ) {
> >     if ( the_ptr ) {
> >       return ( *the_ptr );
> >     }
> >     return ( *the_c_ptr );
> >   }
>
> > };
>
> > double const pi = 3.14159;
> > double e = 2.71828;
>
> > typedef wrapper< double > klass;
>
> > void foo_ref ( reference<double> ) {
> >   std::cout << "reference\n";
>
> > }
>
> > void foo_cref ( const_reference<double> ) {
> >   std::cout << "const reference\n";
>
> > }
>
> > void foo_val ( double ) {
> >   std::cout << "value\n";
>
> > }
>
> > int main ( void ) {
> >   klass rw ( e );
> >   klass ro ( pi );
> >   foo_val( rw );
> >   foo_cref( rw );
> >   foo_ref( rw );
> >   foo_val( ro );
> >   foo_cref( ro );
> >   foo_ref( ro );
>
> > }
>
> > Best,
>
> > Kai-Uwe Bux
>
> In my case the functions foo_ref, foo_cref, foo_val will be given (by
> the client) and may ( and most probably will)  be compiled without any
> knowledge of the types reference and const_reference. So I would need
> it to work with :
>
> --------------------------
> void foo_ref ( double & ) {
>   std::cout << "reference\n";
>
> }
>
> void foo_cref ( const double & ) {
>   std::cout << "const reference\n";
>
> }
>
> void foo_val ( double  ) {
>   std::cout << "value\n";}
>
> --------------------------
>
> (In fact to be even more precise, in my real scenario they will be
> class constructors.)
> When I compile your code with above modifications I get the
> compilation error:
>
> -------------------------------------------------
> main/main.cpp: In function 'int main()':
> main/main.cpp:93:15: error: invalid initialization of reference of
> type 'double&
> ' from expression of type 'klass'
> main/main.cpp:72:6: error: in passing argument 1 of 'void
> foo_ref(double&)'
> main/main.cpp:96:15: error: invalid initialization of reference of
> type 'double&
> ' from expression of type 'klass'
> main/main.cpp:72:6: error: in passing argument 1 of 'void
> foo_ref(double&)'
> ------------------------------------------------
>
> Best
> N

..also if I make the following amendments :
------------------------------------
....
struct someClass
{
        someClass(const double &x_):x(x_){}
        void show()const{std::cout << "x=" <<x <<"\n";}
        const double &x;
};

int main ( void ) {
  double const pi = 3.14159;
  double e = 2.71828;
  klass rw ( e );
  klass ro ( pi );
  foo_val( rw );
  foo_cref( rw );
 // foo_ref( rw );
  foo_val( ro );
  foo_cref( ro );
 // foo_ref( ro );
  someClass s(rw);
  s.show();
  e=0.0;
  s.show();
}

-------------------------
It doesn't work as expected, specifically the last s.show() doesn't
display 0.
Best N

[toc] | [prev] | [next] | [standalone]


#7696

FromKai-Uwe Bux <jkherciueh@gmx.net>
Date2011-07-10 12:03 +0200
Message-ID<ivbtdi$rd2$1@hoshi.visyn.net>
In reply to#7691
Narinder wrote:

[...]
> In my case the functions foo_ref, foo_cref, foo_val will be given (by
> the client) and may ( and most probably will)  be compiled without any
> knowledge of the types reference and const_reference. So I would need
> it to work with :
> 
> --------------------------
> void foo_ref ( double & ) {
>   std::cout << "reference\n";
> }
> 
> void foo_cref ( const double & ) {
>   std::cout << "const reference\n";
> }
> 
> void foo_val ( double  ) {
>   std::cout << "value\n";
> }
> --------------------------

Ok, if cannot fiddle with the signatures, I think you can still avoid 
explicitly mentioning types in client code:

#include <iostream>

struct oops {};

template < typename T >
class const_reference {

  T const * ptr;
  
public:

  const_reference ( T const & r )
    : ptr ( &r )
  {}
  
  T const & get ( void ) {
    return ( *ptr );
  }

  operator T const & ( void ) {
    return ( *ptr );
  }
  
};

template < typename T >
class reference {

  T * ptr;
  
public:

  reference ( T & r )
    : ptr ( &r )
  {}
  
  T & get ( void ) {
    return ( *ptr );
  }

  operator T & ( void ) {
    return ( *ptr );
  }
  
};

template < typename T >
class wrapper {
private:

  T *       the_ptr;
  T const * the_c_ptr;
  
public:
  
  wrapper ( T & ref )
    : the_ptr ( &ref )
    , the_c_ptr ()
  {}

  wrapper ( T const & cref )
    : the_ptr ()
    , the_c_ptr ( &cref )
  {}
  
  operator reference<T> ( void ) {
    std::cout << "convert to non-const reference\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    throw ( oops() );
  }

  operator const_reference<T> ( void ) {
    std::cout << "convert to const reference\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    return ( *the_c_ptr );
  }

  operator T ( void ) {
    std::cout << "convert to value\n";
    if ( the_ptr ) {
      return ( *the_ptr );
    }
    return ( *the_c_ptr );
  }
  
};


template < typename T >
struct call_helper_ref {

  void (&f) ( T & );
  
  call_helper_ref ( void (&fct) ( T & ) )
    : f ( fct )
  {}

  void operator() ( reference<T> arg ) const {
    f( arg );
  }

};

template < typename T >
struct call_helper_cref {

  void (&f) ( T const & );
  
  call_helper_cref ( void (&fct) ( T const & ) )
    : f ( fct )
  {}

  void operator() ( const_reference<T> arg ) const {
    f( arg );
  }

};

template < typename T >
struct call_helper_value {

  void (&f) ( T );
  
  call_helper_value ( void (&fct) ( T ) )
    : f ( fct )
  {}

  void operator() ( T arg ) const {
    f( arg );
  }

};

template < typename T >
call_helper_ref< T > call ( void (&f) ( T & ) ) {
  return ( call_helper_ref<T>(f) );
}

template < typename T >
call_helper_cref< T > call ( void (&f) ( T const & ) ) {
  return ( call_helper_cref<T>(f) );
}

template < typename T >
call_helper_value< T > call ( void (&f) ( T ) ) {
  return ( call_helper_value<T>(f) );
}



// client code
// ===========

double const pi = 3.14159;
double e = 2.71828;

typedef wrapper< double > klass;


void foo_ref ( double & ) {
  std::cout << "reference\n";
}

void foo_cref ( double const & ) {
  std::cout << "const reference\n";
}

void foo_val ( double ) {
  std::cout << "value\n";
}


int main ( void ) {
  klass rw ( e );
  klass ro ( pi );
  call(foo_val)( rw );
  call(foo_cref)( rw );
  call(foo_ref)( rw );
  call(foo_val)( ro );
  call(foo_cref)( ro );
  call(foo_ref)( ro );
}



> (In fact to be even more precise, in my real scenario they will be
> class constructors.)
[...]

Now, that is more tricky as "constructors don't have names". I have to 
ponder whether template magic can detect whether a class has a constructor 
by value, reference, or const-reference.


Best,

Kai-Uwe Bux

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web