3

我正在尝试在模板类中使用 decltype,如下所示:

#include <functional>
template <typename T>
class A
{
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;

    void f();
};

这很好用,但现在我想添加一个明确的专业化:

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

    void f();
};

这次 g++ 报错:

test.cpp:14:33: error: incomplete type 'A<void>' used in nested name specifier

我究竟做错了什么?我正在使用 gcc 4.5。

编辑:如果我void f();按照 Johannes 的建议将声明移到 typedef 上方,我会得到(稍微)不同的错误:

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>::*)()>]'
4

2 回答 2

5

你的订单是错误的。换个试试

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

在主模板中,名称A::f是依赖的,编译器将查找延迟到f声明的点 (A::f在 C++0x 中不再真正依赖,因为A指的是当前实例化,因此指的是当前实例化f的成员,但作为当前规范中有一个漏洞(它与依赖的基类有关),编译器仍然延迟了查找)。在显式特化中,名称是不依赖的,并且会立即进行查找,这就是您需要f在引用它之前声明的原因。

编辑:您错误地使用std::bind. 您提供的第二个参数是 type A<void>,它将被复制/移动std::bind到其创建的调用包装对象中。这需要一个完整的类型A<void>

如果您只想传递A调用成员函数的引用,则可以传递 a declval<A*>(),该std::bind机制同样将其检测为成员指针调用的神奇第一个参数。

但在我看来,你想调查一下std::function<>,而不是这样做std::binddecltype搞砸。毕竟你有一个强大的工具集,但是通过使用这个可疑的decltype表达式,你抛弃了标准库给你的所有通用性,并限制你自己使用那个单一的std::bind表达式。那不好。

于 2011-02-21T08:58:58.430 回答
2

std::bind 需要 A 作为完整类型(参见 Johannes 的回答),因此此时您不能使用它。作为一种解决方法,如果您封装 some_type 这将编译

#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;
};
于 2011-02-21T10:32:29.547 回答