Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #7621 > unrolled thread
| Started by | Narinder <narinder.claire@gmail.com> |
|---|---|
| First post | 2011-07-07 16:34 -0700 |
| Last post | 2011-07-10 12:03 +0200 |
| Articles | 20 — 4 participants |
Back to article view | Back to comp.lang.c++
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
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-07-07 16:34 -0700 |
| Subject | Templated 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]
| From | Alexander Bartolich <alexander.bartolich@gmx.at> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Kai-Uwe Bux <jkherciueh@gmx.net> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Kai-Uwe Bux <jkherciueh@gmx.net> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Kai-Uwe Bux <jkherciueh@gmx.net> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Kai-Uwe Bux <jkherciueh@gmx.net> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Kai-Uwe Bux <jkherciueh@gmx.net> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Kai-Uwe Bux <jkherciueh@gmx.net> |
|---|---|
| Date | 2011-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