このコードをg++4.6および4.8でコンパイルするとエラーが発生しました。g++4.2および4.4は問題ありません。それはバグですか、それとも新しい言語機能ですか?
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;
^
アップデート1:Aはインスタンス化できません。
問題は、コンパイラが「(&* this)-> bar()」行でインスタンス化しようとするが、「this-> bar()」または「(* this).bar()」行ではインスタンス化しないのはなぜですか?
アップデート2:
を使用しようとすると実際にエラーが発生したため、推奨される回避策addressof (object)
は機能しませんstd::bind (&B::bar, this)
。もちろん、実際のコードははるかに複雑で、bind
スタンドアロンでは使用されませんでしたが、問題は単純なstd::bind
式に起因していました。
書き直したり、作り直したりしたくなかったので、 CRTPstd::bind
を使用して機能させる必要がありました。
#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;
}
ただし、このようなエラーと回避策は完全に非論理的です。