Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

C++ Programming

SFINAE for operator->


Hello all,

Is there a way to determine whether a particular type supports the ->
operator at compile time?
I'm trying to write a template function (or a series of overloads)
that will yield the raw pointer at "the end of the arrow". For types
that support the operator, I have a reasonable solution, but I'd like
to have a null pointer returned if the operator isn't supported by a
particular object.

So far I have:

//----begin----
#include <memory>
#include <iostream>

template<typename Ptr, typename T>
Ptr pointer_from_arrowable(T *p) { return p; }

template<typename Ptr, typename Arrowable>
Ptr pointer_from_arrowable(Arrowable &a)
{
    return pointer_from_arrowable<Ptr>(a.operator->());

}

int main()
{
    std::auto_ptr<int> ap(new int(5));
    int *p = pointer_from_arrowable<int *>(ap);
    std::cout << *p << '\n'; // 5
    return 0;
}

//----end----

I thought I might be able to use SFINAE to help the compiler choose an
overload that returns 0 when no operator-> exists, but I end up with
errors (MSVC8 and MinGW g++ 3.4.5) about ambiguous overloads (see end
of post):

//----begin----
#include <memory>
#include <iostream>

template<typename T>
struct mfn_pointer { typedef void (T::*type)(); };

template<typename Ptr, typename T>
Ptr pointer_from_arrowable(T *p) { return p; }

template<typename Ptr, typename Arrowable>
Ptr pointer_from_arrowable(
        Arrowable &a,
        typename mfn_pointer<Arrowable>::type sfinae =
            (typename
mfn_pointer<Arrowable>::type)&Arrowable::operator->
    )
{
    return pointer_from_arrowable<Ptr>(a.operator->());

}

template<typename Ptr, typename Arrowable>
Ptr pointer_from_arrowable(Arrowable &a) { return 0; }

int main()
{
    std::auto_ptr<int> ap(new int(5));
    int *p = pointer_from_arrowable<int *>(ap);
    std::cout << *p << '\n'; // 5
    return 0;

}

//----end----

So is there any way to do what I want?

Here are the compiler errors I got when I attempted the SFINAE code:

MinGW g++ 3.4.5:
--------------------------------------------------
g++ -o arrow.o -c arrow.cpp -ggdb3 -Wall -Wextra -pedantic -ansi -O0 -
Wswitch -D _GLIBCXX_DEBUG
arrow.cpp: In function `int main()':
arrow.cpp:26: error: call of overloaded
`pointer_from_arrowable(std::auto_ptr<int>&)' is ambiguous
arrow.cpp:16: note: candidates are: Ptr
pointer_from_arrowable(Arrowable&, typename
mfn_pointer<Arrowable>::type) [with Ptr = int*, Arrowable =
std::auto_ptr<int>]
arrow.cpp:21: note:                 Ptr
pointer_from_arrowable(Arrowable&) [with Ptr = int*, Arrowable =
std::auto_ptr<int>]
error: system call returned unexpected exit-code 1
--------------------------------------------------

MSVC 8:
--------------------------------------------------
cl /Foarrow.obj /c arrow.cpp /nologo /Od /Zc:forScope,wchar_t /RTCc /
GR /RTCs /Zi /wd4996 /D _CRT_SECURE_NO_DEPRECATE /RTCu /EHsc /MTd /W3
arrow.cpp
arrow.cpp(26) : error C2668: 'pointer_from_arrowable' : ambiguous call
to overloaded function
        arrow.cpp(21): could be 'Ptr
pointer_from_arrowable<int*,std::auto_ptr<_Ty>>(Arrowable &)'
        with
        [
            Ptr=int *,
            _Ty=int,
            Arrowable=std::auto_ptr<int>
        ]
        arrow.cpp(11): or 'Ptr
pointer_from_arrowable<int*,std::auto_ptr<_Ty>>(Arrowable &,void
(__thiscall std::auto_ptr<_Ty>::* )(void))'
        with
        [
            Ptr=int *,
            _Ty=int,
            Arrowable=std::auto_ptr<int>
        ]
        while trying to match the argument list '(std::auto_ptr<_Ty>)'
        with
        [
            _Ty=int
        ]
error: system call returned unexpected exit-code 2
--------------------------------------------------

Kind regards,

Edd

On 3 Jun, 19:54, e@nunswithguns.net wrote:
> Hello all,

> Is there a way to determine whether a particular type supports the ->
> operator at compile time?
> I'm trying to write a template function (or a series of overloads)
> that will yield the raw pointer at "the end of the arrow". For types
> that support the operator, I have a reasonable solution, but I'd like
> to have a null pointer returned if the operator isn't supported by a
> particular object.

<snipped>

assuming T is something like

template<class T>
struct my_ptr
{
       typedef T element_type; // like std::auto_ptr
       element_type * operator->() const;

};

a possible solution would be (tried only on VC8)

template<class T>
struct has_arrowop
{
        typedef char (&yes)[1];
        typedef char (&no)[2];

        template<class T>
        static yes foo(T *, typename T::element_type * (T::*pt)() const =
&T::operator->);

        template<class T>
        static no foo(T const *, bool=false);

        // use the one your compiler supports
        //enum { value = sizeof(foo((T const *)0, true)) !=
sizeof(foo((T*)0)) };
        static const bool value = sizeof(foo((T const *)0, true)) !=
sizeof(foo((T*)0));

};

#include <memory>
#include <iostream>

struct A {};

struct B
{
        typedef int element_type;
        element_type * operator->() const;

};

int main()
{
      std::cout << "A : " << has_arrowop<A>::value << "\n";
      std::cout << "B: " << has_arrowop<B >::value <<'\n';
      std::cout << "std::auto_ptr<A> : " <<
has_arrowop<std::auto_ptr<A> >::value << "\n";

      return 0;

}

DS
Hi DS,

Thanks for your reply.

On 4 Jun, 12:14, dasjotre <dasjo@googlemail.com> wrote:

To keep MinGW g++ happy, I had to parameterise the foo() taking an
element_type pointer by a type named U rather than T (which is the
same as the class parameter type). I also made the other foo a non-
template function, because I don't believe it needs the type
parameter.

But with or without these changes, it doesn't inherently check for
operator->, unless I'm mistaken. Instead, a type is removed from
overload resolution if it doesn't have a nested element_type.

For example, the following type gives a compiler error when used with
has_arrowop<>:

struct X
{
    typedef int element_type;

};

In other words, the existence of operator-> is never checked unless an
element_type exists. If it does exist, it is assumed that an operator-

> is also supplied, which it may not be in cases such as X, above.

Am I interpreting your code correctly?

Perhaps a little more context may help.

I'm actually trying to deduce if a general iterator type supports
operator->.

For output iterators, I can assume not since even though it may be
supplied by a given type of output iterator, it is not a requirement
as far as the standard is concerned.

For all other types of iterator (input, forward, bidirectional and
random access) I thought I might be able to use your trick by
replacing T::element_type with std::iterator_traits<T>::pointer, but
this won't work as every iterator type is *required* to have such a
type defined (I believe) and so sfinae gives me nothing here.

Further more, I cannot just assume that all non-input iterators will
supply an operator-> because that's not the case. They only need
provide one if the expression (*p).m is well formed for an iterator p
and some member m. std::istreambuf_iterator is an example of an input
iterator that doesn't provide an operator->.

So what I've done is assume that the following iterator's don't supply
an operator:
 - output iterators
 - iterators whose value_type is of primitive type

This may be sufficient, but I haven't convinced myself of that quite
yet.

If you have any more thoughts, *please* let me know :)

Thanks again for your response!

Edd

On 4 Jun, 22:37, e@nunswithguns.net wrote:

yes, the element_type is what kicks in SFINAE, not the
existence of operator->. changing to

template<class T, class U>
static yes foo(T *, U * (T::*pt)() const = &T::operator->);

doesn't help. the default parameter is never considered for SFINAE.

the whole thing is useless :-(

> Am I interpreting your code correctly?

better than me.

I'm not very good with the 'chapter and verse' (take
this with a pinch of salt) but I think that all iterators
must provide operator *, input as rvalue and
output as lvalue and all input iterators have to provide
operator-> as well.

the original SGI STL models all iterators, both
input and output by their TrivialIterator model
which requires operator->

> If you have any more thoughts, *please* let me know :)

check:
http://www.boost.org/libs/iterator/doc/pointee.html
and BOOST_MPL_HAS_XXX_TRAIT_DEF

not exactly what you need but you might find
it useful anyway.

good luck ;)

DS.

On 5 Jun, 12:42, dasjotre <dasjo@googlemail.com> wrote:

> the original SGI STL models all iterators, both
> input and output by their TrivialIterator model
> which requires operator->

Actually, that is not correct. only input iterators
are modelled by TrivialIterator.
On 5 Jun, 13:45, dasjotre <dasjo@googlemail.com> wrote:

> On 5 Jun, 12:42, dasjotre <dasjo@googlemail.com> wrote:

> > the original SGI STL models all iterators, both
> > input and output by their TrivialIterator model
> > which requires operator->

> Actually, that is not correct. only input iterators
> are modelled by TrivialIterator.

( doh! )
and obviously only for iterators where (*it).member
is well formed.
On 5 Jun, 13:59, dasjotre <dasjo@googlemail.com> wrote:

> On 5 Jun, 13:45, dasjotre <dasjo@googlemail.com> wrote:

> > On 5 Jun, 12:42, dasjotre <dasjo@googlemail.com> wrote:

> > > the original SGI STL models all iterators, both
> > > input and output by their TrivialIterator model
> > > which requires operator->

> > Actually, that is not correct. only input iterators
> > are modelled by TrivialIterator.

> ( doh! )
> and obviously only for iterators where (*it).member
> is well formed.

This is the catch! So the half-solution I'm currently using is to
assume that an iterator doesn't have an operator-> if either:

(a) it's a pointer (in which case -> can be applied directly)
(b) std::iterator_traits<X>::iterator_category is std::output_iterator
(c) std::iterator_traits<X>::value_type is a primitive type

If an iterator's value type is primitive, operator-> doesn't have to
exist because (*x).m doesn't make sense for any such iterator x in
combination any member name, m.

The case that I can't handle is if a non-output iterator's value type
is non-primitive. Here I always assume that an operator-> does exist,
but this may not be the case in some very rare and strange examples.

I think those rare and strange cases are so rare and strange that in
practice I don't have to worry. But I would still like a solution with
100% coverage :/

You can perhaps imagine some half-arsed class that acts like a
primitive numerical type and whose interface is implemented entirely
in terms of non-member operators.

Edd

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc