为什么C++模板实例化失败



RefPerSys GPLv3+Linux/x86-64项目中(在Debian/Sid系统上(,git commit 37172c9af257865d,使用GCC 10编译,调用为g++ -std=gnu++17 -Og -g3 -Wall -Wextra等。我收到以下错误消息:

refpersys.hh: In instantiation of ‘PaylClass* Rps_ObjectZone::put_new_arg3_payload(Arg1Class, Arg2Class, Arg3Class) [with PaylClass = Rps_PayloadWebex; Arg1Class = long unsigned int; Arg2Class = Onion::Request*; Arg3Class = Onion::Response*]’:
httpweb_rps.cc:314:71:   required from here
refpersys.hh:2162:76: error: no matching function for call to ‘Rps_ObjectZone::rps_allocate4<Rps_PayloadWebex, long unsigned int, Onion::Request*, Onion::Response*>(Rps_ObjectZone*, long unsigned int&, Onion::Request*&, Onion::Response*&)’
2162 | Zone::rps_allocate4<PaylClass,Arg1Class,Arg2Class,Arg3Class>(this,arg1,arg2,arg3);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
In file included from headweb_rps.hh:37,
from httpweb_rps.cc:34:
refpersys.hh:1701:3: note: candidate: ‘template<class ZoneClass, class Arg1Class, class Arg2Class, class Arg3Class, class Arg4Class> static ZoneClass* Rps_QuasiZone::rps_allocate4(Arg1Class, Arg2Class, Arg3Class, Arg4Class)’
1701 |   rps_allocate4(Arg1Class arg1, Arg2Class arg2, Arg3Class arg3, Arg4Class arg4)
|   ^~~~~~~~~~~~~
refpersys.hh:1701:3: note:   template argument deduction/substitution failed:
In file included from headweb_rps.hh:37,
from httpweb_rps.cc:34:
refpersys.hh:2162:76: note:   cannot convert ‘(Rps_ObjectZone*)this’ (type ‘Rps_ObjectZone*’) to type ‘long unsigned int’
2162 | Zone::rps_allocate4<PaylClass,Arg1Class,Arg2Class,Arg3Class>(this,arg1,arg2,arg3);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~

我不容易举一个小例子,但我能够给出以下解释。它是关于用多线程实现(和web接口,以及我们的精确跟踪垃圾收集器(来实现一些动态类型语言(类似专家系统的规则,语义上受Common Lisp的启发(。

主头文件是refpersys.hh,到处都是#included。伴随头文件是headweb_rps.hh,仅与使用libonion的web相关代码相关,libonion是某种HTTP服务器库(名称空间为Onion::(,它是refpersys.hh头的#include

没有在C++意义上使用多重继承。

我们有一个枚举Rps_Type(在文件refpersys.hh的第903行(,它定义了某个标记的并集类型的标记。该标记的并集类型是顶级Rps_TypedZone(在文件refpersys.hh的第1630行中(,具有在refpersys.hh的第1637行中定义的明显构造函数Rps_TypedZone::Rps_TypedZone(const Rps_Type ty)

我们有一个Rps_TypedZoneclass Rps_QuasiZone子类(在文件refpersys.hh的第1646行(。

我们有Rps_QuasiZone的一个class Rps_ZoneValue(在refpersys.hh:1755中(子类。

class Rps_ObjectZone(在refpersys.hh:1964中(是Rps_ZoneValue的一个子类。让我们调用RefPerSys对象Rps_ObjectZone的子类的任何C++实例。

class Rps_ObjectRef(在refpersys.hh:694中(是我们指向Rps_ObjectZone的GC ed智能指针。

class Rps_Value(在refpersys.hh:967中(是一个单字智能指针(有点像Common Lisp中的SBCL值(。

class Rps_Payload(在refpersys.hh:2264中(在Rps_ObjectZone内携带一些可选的额外数据。每个这样的有效载荷都属于一个RefPerSys对象(一些Rps_ObjectZone(,称为其所有者。

Rps_ObjectZoneput_new_arg3_payload模板成员函数很简单(在refpersys.hh:2157和以下行中(,ob_payloadRps_ObjectZone的成员字段,在refpersys.hh:1981:行中声明为std::atomic<Rps_Payload*> ob_payload;

PaylClass* put_new_arg3_payload(Arg1Class arg1, Arg2Class arg2, Arg3Class arg3)
{
std::lock_guard<std::recursive_mutex> gu(ob_mtx);
PaylClass*newpayl =
Rps_QuasiZone::rps_allocate4<PaylClass,Arg1Class,Arg2Class,Arg3Class>(this,arg1,arg2,arg3);
Rps_Payload*oldpayl = ob_payload.exchange(newpayl);
if (oldpayl)
delete oldpayl;
return newpayl;
};                // end put_new_arg3_payload

许多web交互(即HTTP请求,在C++中某些Onion::Request,以及相应的HTTP回复,在C++某些Onion::Reply中,其本身是C++std::ostream的子类(被具体化为文件headweb_rps.hh第65行中声明的class Rps_PayloadWebex的C++实例和Rps_Payload的子类。

模板成员函数Rps_QuasiZone::rps_allocate4(在第refpersys.hh:1699行(定义为:

template <typename ZoneClass, typename Arg1Class, typename Arg2Class, typename Arg3Class, typename Arg4Class>
static ZoneClass*
rps_allocate4(Arg1Class arg1, Arg2Class arg2, Arg3Class arg3, Arg4Class arg4)
{
return new(nullptr) ZoneClass(arg1, arg2, arg3, arg4);
};

我们的";口译员";具体化为class Rps_ProtoCallFrame;,我们(在refpersys.hh第691行(有一个typedef Rps_ProtoCallFrame Rps_CallFrame;

class Rps_ProtoCallFramerefpersys.hh:2823中定义的Rps_TypedZone的一个子类。

故障线路httpweb_rps.cc:314在内部:

Rps_ObjectRef
Rps_PayloadWebex::make_obwebex(Rps_CallFrame*callerframe, Onion::Request*req, Onion::Response*resp,
uint64_t reqnum)
{
RPS_ASSERT(callerframe != nullptr && callerframe->is_good_call_frame());
RPS_ASSERT(req != nullptr);
RPS_ASSERT(resp != nullptr);
auto web_exchange_ob = RPS_ROOT_OB(_8zNtuRpzXUP013WG9S);
RPS_DEBUG_LOG(WEB, "Rps_PayloadWebex::make_obwebex start reqnum#" << reqnum
);
RPS_LOCALFRAME(/*descr:*/ web_exchange_ob,
/*prev:*/callerframe,
/*locals:*/
Rps_ObjectRef obwebex);
_f.obwebex = Rps_ObjectRef::make_object(&_, web_exchange_ob);
auto paylwebex = ////////////////////////////////////// FAULTY LINE BELOW
_f.obwebex->put_new_arg3_payload<Rps_PayloadWebex>(reqnum,req,resp);
RPS_DEBUG_LOG(WEB, "Rps_PayloadWebex::make_obwebex end reqnum#" << reqnum
<< " obwebex=" << _f.obwebex << " startim:" <<  paylwebex->webex_startim);
RPS_ASSERT(paylwebex != nullptr);
return _f.obwebex;
} // end PayloadWebex::make_obwebex

在上述代码中,RPS_ASSERTRPS_ROOT_OBRPS_LOCALFRAMERPS_DEBUG_LOG是C++宏。上述代码的宏扩展为:

Rps_ObjectRef
Rps_PayloadWebex::make_obwebex(Rps_CallFrame*callerframe, Onion::Request*req, Onion::Response*resp,
uint64_t reqnum)
{
do { if (__builtin_expect(!!(!((callerframe != nullptr
&& callerframe->is_good_call_frame()))),0))
{ fprintf(
//# 302 "httpweb_rps.cc" 3
stderr
//# 302 "httpweb_rps.cc"
, "nn" "%s*** RefPerSys ASSERT failed: %s%sn" "%s:%d: {%s}nn", (rps_stderr_istty?(rps_without_terminal_escape?"":"33[1m"):""),
"(callerframe != nullptr && callerframe->is_good_call_frame())",
(rps_stderr_istty?(rps_without_terminal_escape?"":"33[0m"):""),
"httpweb_rps.cc",302,__PRETTY_FUNCTION__);
rps_fatal_stop_at("httpweb_rps.cc",302); }}
while(0);
do
{ if (__builtin_expect(!!(!((req != nullptr))),0)) {
fprintf(
//# 303 "httpweb_rps.cc" 3
stderr
//# 303 "httpweb_rps.cc"
, "nn" "%s*** RefPerSys ASSERT failed: %s%sn" "%s:%d: {%s}nn",
(rps_stderr_istty?(rps_without_terminal_escape?"":"33[1m"):""), "(req != nullptr)",
(rps_stderr_istty?(rps_without_terminal_escape?"":"33[0m"):""), "httpweb_rps.cc",303,__PRETTY_FUNCTION__);
rps_fatal_stop_at("httpweb_rps.cc",303); }} while(0);
do { if (__builtin_expect(!!(!((resp != nullptr))),0)) {
fprintf(
//# 304 "httpweb_rps.cc" 3
stderr
//# 304 "httpweb_rps.cc"
, "nn" "%s*** RefPerSys ASSERT failed: %s%sn" "%s:%d: {%s}nn",
(rps_stderr_istty?(rps_without_terminal_escape?"":"33[1m"):""), "(resp != nullptr)",
(rps_stderr_istty?(rps_without_terminal_escape?"":"33[0m"):""), "httpweb_rps.cc",304,__PRETTY_FUNCTION__);
rps_fatal_stop_at("httpweb_rps.cc",304); }} while(0);
auto web_exchange_ob = rps_rootob_8zNtuRpzXUP013WG9S;
do { if ((rps_debug_flags & (1 << RPS_DEBUG_WEB)))
{ std::ostringstream _logstream_306;
_logstream_306 << "Rps_PayloadWebex::make_obwebex start reqnum#" << reqnum << std::flush;
rps_debug_printf_at("httpweb_rps.cc", 306, RPS_DEBUG_WEB,
"%s", _logstream_306.str().c_str()); } } while (0)
;
struct RpsFrameData308 {/*locals:*/ Rps_ObjectRef obwebex; };
typedef Rps_FieldedCallFrame<RpsFrameData308> Rps_FldCallFrame308;
class Rps_FrameAt308 : public Rps_FldCallFrame308
{ public:
Rps_FrameAt308(Rps_ObjectRef obd308, Rps_CallFrame* prev308) :
Rps_FldCallFrame308(obd308, prev308) { }; };
Rps_FrameAt308 _((/*descr:*/ web_exchange_ob),(/*prev:*/callerframe));
auto& _f = *_.fieldsptr();

;
_f.obwebex = Rps_ObjectRef::make_object(&_, web_exchange_ob);
auto paylwebex =
_f.obwebex->put_new_arg3_payload<Rps_PayloadWebex>(reqnum,req,resp);
do { if ((rps_debug_flags & (1 << RPS_DEBUG_WEB)))
{ std::ostringstream _logstream_315;
_logstream_315 << "Rps_PayloadWebex::make_obwebex end reqnum#"
<< reqnum << " obwebex=" << _f.obwebex << " startim:"
<< paylwebex->webex_startim << std::flush; rps_debug_printf_at("httpweb_rps.cc",
                315, RPS_DEBUG_WEB, "%s",
                _logstream_315.str().c_str()); } } while (0)
;
do { if (__builtin_expect(!!(!((paylwebex != nullptr))),0)) {
fprintf(
//# 317 "httpweb_rps.cc" 3
stderr
//# 317 "httpweb_rps.cc"
, "nn" "%s*** RefPerSys ASSERT failed: %s%sn" "%s:%d: {%s}nn",
(rps_stderr_istty?(rps_without_terminal_escape?"":"33[1m"):""), "(paylwebex != nullptr)",
(rps_stderr_istty?(rps_without_terminal_escape?"":"33[0m"):""), "httpweb_rps.cc",317,__PRETTY_FUNCTION__);
rps_fatal_stop_at("httpweb_rps.cc",317); }} while(0);
return _f.obwebex;
} // end PayloadWebex::make_obwebex

我做错了什么?

错误消息末尾的这一行很清楚,它暗示long unsigned int应该寻找。。。

cannot convert ‘(Rps_ObjectZone*)this’ (type ‘Rps_ObjectZone*’) to type ‘long unsigned int’   

这条,与错误消息开头的这条线结盟:

refpersys.hh:2162:76: error: no matching function for call to Rps_ObjectZone::rps_allocate4<Rps_PayloadWebex, long unsigned int, Onion::Request*, Onion::Response*>(Rps_ObjectZone*, long unsigned int&, Onion::Request*&, Onion::Response*&)’

这是第一行错误:

refpersys.hh: In instantiation of ‘PaylClass* Rps_ObjectZone::put_new_arg3_payload(Arg1Class, Arg2Class, Arg3Class) [with PaylClass = Rps_PayloadWebex; Arg1Class = long unsigned int; Arg2Class = Onion::Request*; Arg3Class = Onion::Response*

重要部件为Arg1Class = long unsigned int;

所有这些都意味着long unsigned int(变量reqnum的类型对于调用中的第一个参数不是有效类型_f.obwebex->put_new_arg3_payload<Rps_PayloadWebex>();

ArgClass1似乎至少应该是某种指针,更有可能是指向从Rps_ObjectZone派生的类型的指针。

我还没有使用这个特定的库,但这就是错误消息的含义。

我认为最可能的错误是混淆了这个函数调用的前两个参数的顺序。

Rps_QuasiZone::rps_allocate4<PaylClass,Arg1Class,Arg2Class,Arg3Class> (this,arg1,arg2,arg3);

在那里,或者在对类ZoneClass的构造函数的调用中。

参数的混合顺序只是一个假设,我还没有看到ZoneClass类的构造函数。

顺便说一句:如果Arg1Class必须可转换为ZoneClass*,这意味着有问题的代码正在声明不应该声明的模板参数类型。

相关内容

最新更新