我正在尝试在模板类中使用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();
的声明移到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>::*)()>]'
答案 0 :(得分:4)
您的订单有误。尝试交换它
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<void>
类型,它将被std::bind
复制/移动到其创建的调用包装器对象中。这需要完整的类型A<void>
。
如果您只想传递对其中调用成员函数的A
的引用,您可以传递declval<A*>()
std::bind
机制同样检测为神奇的第一个参数成员指针调用。
但在我看来,您希望调查std::function<>
,而不是执行此std::bind
和decltype
混乱。毕竟你有一个强大的工具集,但通过使用这个令人怀疑的decltype
表达式,你抛弃了标准库给你的所有通用性,并限制自己使用那个单std::bind
表达式。那不好。
答案 1 :(得分:2)
std :: bind需要A作为完整类型(请参阅Johannes的回答),因此您不能在此时使用它。作为解决方法,如果您将some_type封装为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;
};