|
Boost : |
Subject: [boost] help detecting presence of operator[]
From: Jeffrey Hellrung (jhellrung_at_[hidden])
Date: 2010-01-22 15:52:52
Hi all,
I'm trying to perform a compile-time check to determine if a class has
an operator[]. I'm using a "trick" I think I've seen in Adobe's library
and on this list in the past:
-------- BEGIN CODE --------
template< class T >
struct has_op_bracket
{
struct base_t { void operator[]( int ); };
struct derived_t : T, base_t { };
template< void (base_t::*)( int ) > struct sfinae { typedef char
type; };
template< class U > static typename sfinae< &U::operator[] >::type
is_ambiguous(int);
template< class U > static int is_ambiguous(...);
static const bool value = sizeof( is_ambiguous< derived_t >(0) ) != 1;
};
-------- END CODE --------
The way I understand this working is if T has no operator[], then
&derived_t::operator[] unambiguously refers to *base_t::operator[], and
so the first is_ambiguous overload is selected. Otherwise,
&derived_t::operator[] is ambiguous, which is sufficient (I guess...?)
for SFINAE to kick in, and the second is_ambiguous overload is selected.
Now given the following definitions of X0 and X1:
-------- BEGIN CODE --------
struct X0 { };
struct X1 { void operator[](void*); };
-------- END CODE --------
then the following static assertions pass, as expected:
-------- BEGIN CODE --------
BOOST_STATIC_ASSERT(( !has_op_bracket<X0>::value ));
BOOST_STATIC_ASSERT(( has_op_bracket<X1>::value ));
-------- END CODE --------
However, if X2 is defined as
-------- BEGIN CODE --------
struct X2
{
template< class T > struct R : T { };
template< class T >
typename R<T>::type operator[](T);
};
-------- END CODE --------
then has_op_bracket<X2>::value fails to compile on MSVC9, but (according
to Dinkum Exam[1]) it does compile just fine on "EDG/C++". The error in
MSVC9 is
-------- BEGIN OUTPUT --------
error C2516: 'T' : is not a legal base class
1> d:\test\main.cpp(9) : see declaration of 'T'
1> d:\test\main.cpp(9) : see reference to class template
instantiation 'X2::R<T>' being compiled
1> with
1> [
1> T=int
1> ]
1> d:\test\main.cpp(21) : see reference to class template
instantiation 'has_op_bracket<T>' being compiled
1> with
1> [
1> T=X2
1> ]
-------- END OUTPUT --------
generated by the following program:
-------- BEGIN CODE --------
template< class T >
struct has_op_bracket
{
struct base_t { void operator[]( int ) const; };
struct derived_t : T, base_t { };
template< void (base_t::*)( int ) const > struct sfinae { typedef
char type; };
template< class U > static typename sfinae< &U::operator[] >::type
is_ambiguous(int);
template< class U > static int is_ambiguous(...);
static const bool value = sizeof( is_ambiguous< derived_t >(0) ) !=
1; // line 9
};
struct X2
{
template< class T > struct R : T { };
template< class T >
typename R<T>::type operator[](T);
};
int main()
{
has_op_bracket<X2>::value; // line 21
return 0;
}
-------- END CODE --------
What I don't understand is why MSVC is trying to instantiate R<int>. It
seems to be grabbing the int from the parameter type of the member
function pointer template parameter in sfinae, which doesn't seem like
the right thing to do. I can change that parameter to anything else (as
long as it doesn't have a nested type typedef) and the error persists.
Is MSVC correct, or is this a compiler bug? Either way, is there an
alternative, more portable approach to achieve the desired effect?
Thanks in advance,
- Jeff
[1] http://www.dinkumware.com/exam/default.aspx
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk