Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #7698
| From | Kai-Uwe Bux <jkherciueh@gmx.net> |
|---|---|
| Newsgroups | comp.lang.c++ |
| Subject | Re: Templated Casting operators |
| Followup-To | comp.lang.c++ |
| Date | 2011-07-10 13:43 +0200 |
| Organization | University of Bielefeld |
| Message-ID | <ivc3a0$t5j$1@hoshi.visyn.net> (permalink) |
| References | (7 earlier) <iv9ed1$67q$1@hoshi.visyn.net> <b781d567-f97a-4951-b3fb-b6702884a8d8@h12g2000vbx.googlegroups.com> <ivanek$g9k$1@hoshi.visyn.net> <129c15d7-bb88-4a2c-a42e-c9292e491a8a@w4g2000yqm.googlegroups.com> <6def1a38-0e27-4b1d-b3cc-9d8231b08569@t9g2000vbv.googlegroups.com> |
Followups directed to: comp.lang.c++
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
Back to comp.lang.c++ | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
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
csiph-web