Re: Templated Casting operators
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 deducti=
on
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 becaus=
e v is unable
to give up its const ref
// but as we have seen gcc call=
s 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