这个可变参数模板示例有什么问题?
基类是:
#include <memory>
namespace cb{
template< typename R, typename ... Args >
class CallbackBase
{
public:
typedef std::shared_ptr< CallbackBase< R, Args... > >
CallbackPtr;
virtual ~CallbackBase()
{
}
virtual R Call( Args ... args) = 0;
};
} // namespace cb
派生类是这样的:
namespace cb{
template< typename R, typename ... Args >
class FunctionCallback : public CallbackBase< R, Args... >
{
public:
typedef R (*funccb)(Args...);
FunctionCallback( funccb cb_ ) :
CallbackBase< R, Args... >(),
cb( cb_ )
{
}
virtual ~FunctionCallback()
{
}
virtual R Call(Args... args)
{
return cb( args... );
}
private:
funccb cb;
};
} // namespace cb
要创建的函数:
namespace cb{
template < typename R, typename ...Args >
typename CallbackBase< R, Args... >::CallbackBasePtr
MakeCallback( typename FunctionCallback< R, Args... >::funccb cb )
{
typename CallbackBase< R, Args... >::CallbackBasePtr
p( new FunctionCallback< R, Args... >( cb )
);
return p;
}
} // namespace cb
示例:
bool Foo_1args( const int & t)
{
return true;
}
int main()
{
auto cbObj = cb::MakeCallback( & Foo_1args );
}
我不断收到此错误:
error: no matching function for call to ‘MakeCallback(bool (*)(const int&))’
error: unable to deduce ‘auto’ from ‘<expression error>’
我尝试更改它,但我不知道如何修复。
那么,到底出了什么问题呢?以及如何解决这个例子?
The base class is :
#include <memory>
namespace cb{
template< typename R, typename ... Args >
class CallbackBase
{
public:
typedef std::shared_ptr< CallbackBase< R, Args... > >
CallbackPtr;
virtual ~CallbackBase()
{
}
virtual R Call( Args ... args) = 0;
};
} // namespace cb
Derived class is this :
namespace cb{
template< typename R, typename ... Args >
class FunctionCallback : public CallbackBase< R, Args... >
{
public:
typedef R (*funccb)(Args...);
FunctionCallback( funccb cb_ ) :
CallbackBase< R, Args... >(),
cb( cb_ )
{
}
virtual ~FunctionCallback()
{
}
virtual R Call(Args... args)
{
return cb( args... );
}
private:
funccb cb;
};
} // namespace cb
Function to create :
namespace cb{
template < typename R, typename ...Args >
typename CallbackBase< R, Args... >::CallbackBasePtr
MakeCallback( typename FunctionCallback< R, Args... >::funccb cb )
{
typename CallbackBase< R, Args... >::CallbackBasePtr
p( new FunctionCallback< R, Args... >( cb )
);
return p;
}
} // namespace cb
And the example :
bool Foo_1args( const int & t)
{
return true;
}
int main()
{
auto cbObj = cb::MakeCallback( & Foo_1args );
}
I keep getting this error :
error: no matching function for call to ‘MakeCallback(bool (*)(const int&))’
error: unable to deduce ‘auto’ from ‘<expression error>’
I tried to change it, but I couldn't figure out how to fix.
So, what is wrong? And how to fix this example?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
通过一个更简单的例子,这个问题可能会有意义。尝试在这里找出问题:
问题是编译器无法推断出
T
应该是什么;它没有在任何地方直接使用。您必须显式提供它:foo(5)
,或者让它以其他方式推断它:这是有道理的:编译器如何找出哪个
T< /code> 提供给
id
会导致id::type
匹配吗?可能会有专业化,而且如果可能的话,整个事情无论如何都会很昂贵。同样,编译器无法推断出 R 和 Args。相反,您应该这样做:
最后,您还有其他需要修复的小问题,Xeo 已概述。
The problem might make sense with a simpler example. Try identifying the problem here:
The problem is that the compiler cannot deduce what
T
should be; it's not directly used anywhere. You'd have to explicitly provide it:foo<int>(5)
, or let it deduce it in some other way:This makes sense: how could the compiler figure out which
T
's, supplied toid
, result inid<T>::type
matching? There could be specializations, and the entire thing would be costly anyway, if possible.Likewise, there's nothing the compiler has available to deduce
R
andArgs
. Instead, you should do this:Finally, you have other minor issues that need fixing, which Xeo has outlined.
回想一下我在其他答案的评论中提到的内容:
MakeCallback
参数是不可推导的。MakeCallback
返回类型是错误的。它应该是CallbackPtr
,因为CallbackBasePtr
typedef 不存在。这导致 SFINAE 即使参数已修复,也不会将您的函数视为可能调用的函数。new FunctionCallback(&cb)
To recollect what I mentioned in the comments of the other answers:
MakeCallback
was non-deducible.MakeCallback
was wrong. It should beCallbackPtr
, as aCallbackBasePtr
typedef doesn't exist. This lead to SFINAE kicking in and not considering your function as a possible function to call even when the argument was fixed.FunctionCallback
constructor wanted afunccb*
pointer, whilefunccb
already is a (function-)pointer, so you would have to pass a pointer-to-function-pointer, eg.new FunctionCallback(&cb)
使用
比重新发明它更好……直接从编译器的实现中复制也更好。一般来说,使用较少的模板参数也是一件好事。
但是,解决这些问题总是很诱人……所以,知道我在做什么,但现在不直接看它,这就是我处理它的方法。
简单地
调用
函子的代码不会专门针对不同类型的函子,因此它应该在一般模板情况下。要对通用模板进行细微调整,特征类最适合。
It's better to use
<functional>
than to reinvent it… It's also better to copy directly from your compiler's implementation.Generally, using fewer template parameters is a good thing, too.
But, it's always tempting to solve these problems… so, knowing what I do, but not looking directly at that right now, here is how I'd handle it.
The code to simply
Call
a functor will not be specialized for the different kinds of functors, so it should be in the general template case.To make minor adjustments to the general template, a traits class serves best.
修复了一些 type-o 并专门化了 MakeCallback 以接受函数指针。正如 GMan 所说,MakeCallback 的模板参数处于不可推导的上下文中。
更新:
C++ 标准在 14.8.2.5 [temp.deduct.type] 第 5 - 6 段中定义了非推导上下文。那里有一个我赢得的项目符号列表不声称完全理解。我的标记是:
Fixed some type-o's and specialized MakeCallback to accept function pointers. As GMan said, your template arguments to MakeCallback are in a non-deducible context.
Update:
The C++ standard defines non-deduced context in 14.8.2.5 [temp.deduct.type], paragraphs 5 - 6. There is a bulleted list there which I won't claim to fully understand. The marker for me is: