I am trying to use decltype inside a template class as follows:
#include <functional>
template <typename T>
class A
{
typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
void f();
};
That works fine, but now I’d like to add an explicit specialization:
template <>
class A<void>
{
typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
void f();
};
This time g++ gives an error:
test.cpp:14:33: error: incomplete type 'A<void>' used in nested name specifier
What am I doing wrong? I am using gcc 4.5.
EDIT: If I move the declaration of void f(); to above the typedef, as suggested by Johannes, I get (slightly) different errors:
test.cpp:15:62: error: invalid use of incomplete type 'class A<void>'
test.cpp:13:1: error: declaration of 'class A<void>'
test.cpp:15:62: error: initializing argument 2 of 'std::_Bind<typename std::_Maybe_wrap_member_pointer<_Tp>::type(_ArgTypes ...)> std::bind(_Functor, _ArgTypes ...) [with _Functor = void (A<void>::*)(), _ArgTypes = {A<void>}, typename std::_Maybe_wrap_member_pointer<_Tp>::type = std::_Mem_fn<void (A<void>::*)()>]'
test.cpp:15:62: error: invalid use of incomplete type 'class A<void>'
test.cpp:13:1: error: declaration of 'class A<void>'
test.cpp:15:62: error: initializing argument 2 of 'std::_Bind<typename std::_Maybe_wrap_member_pointer<_Tp>::type(_ArgTypes ...)> std::bind(_Functor, _ArgTypes ...) [with _Functor = void (A<void>::*)(), _ArgTypes = {A<void>}, typename std::_Maybe_wrap_member_pointer<_Tp>::type = std::_Mem_fn<void (A<void>::*)()>]'
Your order is wrong. Try exchanging it
In the primary template, the name
A::fwas dependent and the compiler delayed lookup to a point wherefwas declared (A::fis not really dependent in C++0x anymore, sinceArefers to the current instantiation and thereforfto a member of the current instantiation, but as there is a loophole in the current specification (it has to do with dependent base classes), the compiler delayed the lookup nontheless). In the explicit specialization, the name is not dependent and lookup is done immediately, which is the reason you need to declarefbefore referring to it.Edit: You are wrongly using
std::bind. The second argument you give is of typeA<void>, which will be copied/moved bystd::bindinto its created call wrapper object. This requires a complete typeA<void>.If you want to merely pass a reference to
Aon which the member function is called, you can pass adeclval<A*>(), which thestd::bindmechanism equally detects as magical first argument to a member pointer invocation.But it seems to me you want to look into
std::function<>, instead of doing thisstd::bindanddecltypemess. After all you have a powerful toolset given, but by using this doubtfuldecltypeexpression, you throw away all the genericity the Standard library gives you and restrict yourself to use of that singlestd::bindexpression. That’s no good.