类模板特化中的 decltype
我试图在模板类中使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你的订单是错误的。尝试交换它
在主模板中,名称
A::f
是相关的,并且编译器将查找延迟到声明f
的点 (A::f
在 C++0x 中不再真正依赖,因为A
引用当前实例化,因此f
引用当前实例化的成员,但正如是当前规范中的一个漏洞(它与依赖基类有关),但编译器延迟了查找)。在显式特化中,名称是不相关的,查找会立即完成,这就是您需要在引用它之前声明f
的原因。编辑:您错误地使用了
std::bind
。您给出的第二个参数的类型为A
,它将由std::bind
复制/移动到其创建的调用包装器对象中。这需要一个完整的类型A
。如果您只想传递对调用成员函数的
A
的引用,则可以传递declval()
,其中std::bind
机制同样检测为成员指针调用的神奇第一个参数。但在我看来,你想研究一下
std::function<>
,而不是做这个std::bind
和decltype
混乱。毕竟,您已经给出了强大的工具集,但是通过使用这个可疑的 decltype 表达式,您抛弃了标准库为您提供的所有通用性,并限制自己使用单个 std::bind 表达式。那可不好。Your order is wrong. Try exchanging it
In the primary template, the name
A::f
was dependent and the compiler delayed lookup to a point wheref
was declared (A::f
is not really dependent in C++0x anymore, sinceA
refers to the current instantiation and thereforf
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 declaref
before 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::bind
into its created call wrapper object. This requires a complete typeA<void>
.If you want to merely pass a reference to
A
on which the member function is called, you can pass adeclval<A*>()
, which thestd::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 thisstd::bind
anddecltype
mess. After all you have a powerful toolset given, but by using this doubtfuldecltype
expression, you throw away all the genericity the Standard library gives you and restrict yourself to use of that singlestd::bind
expression. That's no good.std::bind 需要 A 作为完整类型(请参阅 Johannes 的回答),因此此时您不能使用它。作为解决方法,如果封装 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: