I have the following question
Is there a way to find out if one type is expose a operator [] or not?
I've been trying the something as:
template< class T >
bool IsHas( )
{
T::TYPE ( T::*test )( ) const = &T::operator[];
return *test != NULL;
}
which doesn't compile
Does anybody know how I can perform such a check?
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
>Hi,
>
>I have the following question
>
>Is there a way to find out if one type is expose a operator [] or not?
>
>I've been trying the something as:
>
>template< class T >
>bool IsHas( )
>{
> T::TYPE ( T::*test )( ) const = &T::operator[];
> return *test != NULL;
>}
This is a template function. With template functions the type T is
determined when you call the function at compile time
e.g.
IsHas<vector<int> >();
and if TYPE is a type declared in type T then you need typename
typename T::TYPE ( T::*test )() etc
>
>which doesn't compile
>
>Does anybody know how I can perform such a check?
Not at runtime you can't. Your code above will fail at compile time
if there is no operator[]
Why would you want to find out at runtime - its too late to decide to
call it - you have to decide that at compile time.
Graeme
[ ... ]
> >Does anybody know how I can perform such a check?
>
> Not at runtime you can't.
Yes you can, although your compiler might not be aware of this ;-). The
following code will do it
template <class T>
class has_subscript_operator
{
private:
typedef char (&yes)[3];
typedef char (&no)[23];
template <size_t> struct helper {};
template <class U> static yes foo( helper<sizeof( &U::operator[] )> * );
template <class U> static no foo( ... );
public:
enum { value = sizeof(foo<T>(0)) == sizeof(yes) };
};
// Usage:
std::cout << has_subscript_operator< my_class >::value << std::endl;
It is possible to write a version of this that actually compiles in current
compiles, but it's rather messy.
--
Richard Smith
On which compiler did you try this ?
Are you sure that it will work ?
Isn't more correct solution for this to be the following:
template< typename T >
class has_subscript_operator
{
private:
typedef char (&yes)[3];
typedef char (&no)[23];
template< size_t > struct helper {};
template< typename U > static yes foo( helper< sizeof( &U::operator[](0) ) > * );
template< typename U > static no foo( ... );
public:
enum { value = sizeof(foo<T>(0)) == sizeof(yes) };
};
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
>
>template <class T>
>class has_subscript_operator
>{
>private:
> typedef char (&yes)[3];
> typedef char (&no)[23];
> template <size_t> struct helper {};
> template <class U> static yes foo( helper<sizeof( &U::operator[] )> * );
> template <class U> static no foo( ... );
>public:
> enum { value = sizeof(foo<T>(0)) == sizeof(yes) };
>};
>
>// Usage:
>std::cout << has_subscript_operator< my_class >::value << std::endl;
Wow - more template tricks I didn't know. The Borland compiler gets
internal compiler errors. The Comeau compiler compiles the code ok
but gave the "wrong" answer.
I spent a while fiddling with it and it seems happy to choose "yes
foo( .. sizeof(U) ... ) but when accessing a member of U is
involved, it fails to find a match for foo<T>(0) ( if I comment out
"no foo ... " )
As you said, its messy - but interesting.
Graeme
[ to moderator - I posted this before but it didn't turn up yet other
posts I sent after it, have turned up so I am reposting this - my
apologies if it turns up twice ]
{ There are time warps. If you get a tracking number, ask us about
the status. If you do not, assume it got lost getting to us. The
assumption may be wrong and it could show up months later. :) -mod/jep
>
>template <class T>
>class has_subscript_operator
>{
>private:
> typedef char (&yes)[3];
> typedef char (&no)[23];
> template <size_t> struct helper {};
> template <class U> static yes foo( helper<sizeof( &U::operator[] )> * );
> template <class U> static no foo( ... );
>public:
> enum { value = sizeof(foo<T>(0)) == sizeof(yes) };
>};
>
>// Usage:
>std::cout << has_subscript_operator< my_class >::value << std::endl;
>
>
>It is possible to write a version of this that actually compiles in current
>compiles, but it's rather messy.
Wow - more template tricks I didn't know. The Borland compiler gets
internal compiler errors. The Comeau compiler compiles the code ok
but gave the "wrong" answer.
I spent a while fiddling with it and it seems happy to choose "yes
foo( .. sizeof(U) ... ) but when accessing a member of U is
involved, it fails to find a match for foo<T>(0) ( if I comment out
"no foo ... " )
As you said, its messy - but interesting.
Graeme
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
The only non-cosmetic difference I can see is the presence of this (0). I
really don't think that it is legal to have this here. What is it supposed
to do? Did you mean
(((U*)0)->*&U::operator[])(0)
or perhaps
(*((U*)0))[0]
?
If so, then these are valid possibilities, but do something slightly
different. My code tests for an operator[] of *any* signature (although it
will probably fail in the presence of overloads -- I must think that aspect
out more fully), these two alternatives test for the presence of an
operator[] that takes an intergral (or convertable from integral) argument.
Both would have their uses, but do different things.
> template< typename U > static no foo( ... );
> public:
> enum { value = sizeof(foo<T>(0)) == sizeof(yes) };
> };
--
Richard Smith
> Wow - more template tricks I didn't know. The Borland compiler gets
> internal compiler errors. The Comeau compiler compiles the code ok
> but gave the "wrong" answer.
Yes. To my knowledge there are no compilers that are yet up to the
challenge.
> I spent a while fiddling with it and it seems happy to choose "yes
> foo( .. sizeof(U) ... ) but when accessing a member of U is
> involved, it fails to find a match for foo<T>(0) ( if I comment out
> "no foo ... " )
The problem (with Comeau at least) is that as far as I can tell, it doesn't
properly obey the letter of the rules for function overloading. If you're
interested in more examples see the "is_enum<T> ATTN: Andrei Alexandrescu
and ilk" thread here and the "14.8.2 Clarification?" thread on comp.std.c++,
mid to late last month.
--
Richard Smith
[ compile time testing for operator[] ]
> On which compiler did you try this ?
Many. None of which were up to the challenge.
> Are you sure that it will work ?
I'm fairly sure that the idea is legal. It's possible that there are errors
in my code -- after all, I couldn't compile it. If you're after a version
that does compile, then the following works in Comeau 4.2.45.2 but only
tests for a particular signature operator[], in this case int
operator[](unsigned) const. Attempts to abstract the required signature of
the operator[] caused Comeau to seg fault ;-(.
namespace details
{
template <class T, int (T::*)(unsigned) const>
struct type_fwd
{
typedef T type;
};
template <class T, class U>
struct has_subscript_helper
{
enum { value = false };
};
template <class T>
struct has_subscript_helper
<T, typename type_fwd<T, &T::operator[]>::type>
{
enum { value = true };
};
}
template <class T>
struct has_subscript_operator
: public details::has_subscript_helper<T, T>
{};
struct foo
{};
struct bar
{
int operator[](unsigned) const;
};
template <bool> struct static_assert;
template <> struct static_assert<true> {};
int main()
{
static_assert< ! has_subscript_operator<foo>::value >();
static_assert< has_subscript_operator<bar>::value >();
}
--
Richard Smith