开发者

decltype in class template specialization

I am trying to use declt开发者_如何学JAVAype 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

template <>
class A<void>
{    
    void f();
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
};

In the primary template, the name A::f was dependent and the compiler delayed lookup to a point where f was declared (A::f is not really dependent in C++0x anymore, since A refers to the current instantiation and therefor f to 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 declare f before referring to it.

Edit: You are wrongly using std::bind. The second argument you give is of type A<void>, which will be copied/moved by std::bind into its created call wrapper object. This requires a complete type A<void>.

If you want to merely pass a reference to A on which the member function is called, you can pass a declval<A*>(), which the std::bind mechanism 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 this std::bind and decltype mess. After all you have a powerful toolset given, but by using this doubtful decltype expression, you throw away all the genericity the Standard library gives you and restrict yourself to use of that single std::bind expression. That's no good.


std::bind requires A as a complete type (see answer by Johannes) and therefore you cannot use it at this point. As a workaround, if you encapsulate the some_type this will compile:

#include <functional>

template <typename T>
class A
{
  void f();
  struct some_type_helper
  {
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
  };
};

template <>
class A<void>
{
  void f();
  struct some_type_helper;
};

struct A<void>::some_type_helper
{
  typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
};
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜