I got the errors compiling this code with g++ 4.6 and 4.8. g++ 4.2 and 4.4 is OK. Is it a bug or some new language feature?
template <typename T>
struct A { typedef typename T::value_type type; };
template <typename U>
struct B
{
void bar () { }
void foo ()
{
// OK
this->bar ();
// OK
(*this).bar ();
// Error in g++ 4.6-4.8
// leads to full instantiating of template arg "U"
(&*this)->bar ();
}
};
int main ()
{
B< A<void> > b;
b.foo ();
return 0;
}
g++ inst.cc
inst.cc: In instantiation of ‘struct A<void>’:
inst.cc:20:5: required from ‘void B<U>::foo() [with U = A<void>]’
inst.cc:27:10: required from here
inst.cc:3:34: error: ‘void’ is not a class, struct, or union type
typedef typename T::value_type type;
^
Update 1: A cannot be instantiated, I know.
The question is: why the compiler tries to instantiate it at "(&*this)->bar ()" line, but not at "this->bar ()" or "(*this).bar ()" lines?
Update 2:
The suggested workaround with addressof (object)
is not working for me, because actually I got the error when I tried to use std::bind (&B::bar, this)
. The real code is much more complex of course and the bind
was not used standalone, but the problem was traced to the simple std::bind
expression.
I did not want to rewrite or reinvent std::bind
, so I had to use CRTP to make it work:
#include <tr1/functional>
template <typename T>
struct A { typedef typename T::value_type type; };
template <typename Derived, typename U>
struct B
{
Derived* derived (void) { return static_cast<Derived*>(this); }
void bar () { }
void foo ()
{
// error with recent compiler.
// std::tr1::bind (&B::bar, this) ();
// now ok
std::tr1::bind (&Derived::bar, derived ()) ();
}
};
struct C: B<C, A<void> >
{
};
int main ()
{
C c;
c.foo ();
return 0;
}
I find such errors and workarounds to be completely illogical though.