类模板特化中的 decltype

发布于 2024-10-18 03:00:21 字数 1683 浏览 7 评论 0原文

我试图在模板类中使用 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

我做错了什么?我正在使用海湾合作委员会4.5。

编辑:如果我按照 Johannes 的建议将 void f(); 的声明移到 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>::*)()>]'

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

逆光飞翔i 2024-10-25 03:00:21

你的订单是错误的。尝试交换它

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。您给出的第二个参数的类型为 A,它将由 std::bind 复制/移动到其创建的调用包装器对象中。这需要一个完整的类型A

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

但在我看来,你想研究一下 std::function<>,而不是做这个 std::binddecltype 混乱。毕竟,您已经给出了强大的工具集,但是通过使用这个可疑的 decltype 表达式,您抛弃了标准库为您提供的所有通用性,并限制自己使用单个 std::bind 表达式。那可不好。

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.

随遇而安 2024-10-25 03:00:21

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;
};

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;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文