c++ - 如何修复成员函数上的“声明为'静态'但从未定义”?
问题描述
我正在实现一个 IRC 客户端(我知道有点不合时宜),并且由于这个令人困惑的编译警告(g++ 7.4.0)而碰壁了。这在 clang 下根本不会发生,但我更喜欢 g++ 并希望尽可能安抚它。
In file included from src/client/server_context.cpp:3:0:
src/protocol/numeric.h:52:15: error: ‘silica::protocol::prototype
silica::protocol::numeric_impl<NumericCode, SymbolicName, NumArgs>::
getPrototype() const [with const char* NumericCode =
(& silica::protocol::NUM_RPL_ENDOFMOTD);
const char* SymbolicName = (& silica::protocol::SYM_RPL_ENDOFMOTD);
int NumArgs = 0]’ declared ‘static’ but never defined [-Werror=unused-function]
prototype getPrototype() const override { return s_prototype; }
模板的其他实例存在重复项。
但是,我完全不知道该函数是静态的(我想它是在谈论翻译单元独有的可见性,而不是面向对象意义上的“静态”)或未定义的(定义就在那里!) .
包含此方法的模板已在我的代码中的其他地方成功实例化,并且仅当我getPrototype()
在此特定上下文中调用时才会发生上述呕吐。
现在,一些上下文:
numeric_impl
是用于定义 RFC 1459 数字代码的模板类- 的每个实例化
numeric_impl
都来自numeric_base
numeric_base
派生自protobase
(表示协议消息的基类)- 对于每种唯一类型的消息,都存在一个
prototype
消息(基本上只是一个包含其名称和消息类型的其他属性的结构) protobase
定义virtual prototype getPrototype()
以便我可以在运行时确定特定消息的类型- 每个特定的消息类型也有一个
static prototype Prototype()
对检查等有用的东西someMessage.getPrototype() == some_message_type::Prototype()
触发错误的代码基本上如下:
void server_context::connect(/* omitted irrelevant args */) {
// Omitted irrelevant code that attempts to connect to the server
// This call waits for a reply to the command that was sent above
std::shared_ptr<protobase> res = client->wait_for(
{err_nonicknamegiven::Prototype(), err_erroneusnickname::Prototype(), err_nicknameinuse::Prototype(),
err_nickcollision::Prototype(), err_needmoreparams::Prototype(), err_alreadyregistred::Prototype(),
rpl_endofmotd::Prototype()},
std::chrono::seconds(5));
// Ultimately, i want to check that 'res' was of a particular type,
// which i intended to do by comparing its prototype against one of
// the above prototypes, but this is a stand-in for that.
// Removing this line makes the warning go away.
std::cout << res->getPrototype().commandSymbol() << std::endl;
return res;
}
值得注意的是,getPrototype
这里激怒编译器的调用是 onprotobase
而不是在 instantiation 上numeric_impl
,这使得警告更加混乱。
有趣的是,删除getPrototype
上面的调用会导致不会发出警告。或者,创建所有使用的数字类型的实例(并调用getPrototype
它们)也可以让它消失:
std::cout << err_nonicknamegiven(std::list<std::string>{}).getPrototype().commandSymbol() << std::endl;
std::cout << err_erroneusnickname(std::list<std::string>{}).getPrototype().commandSymbol() << std::endl;
std::cout << err_nicknameinuse(std::list<std::string>{}).getPrototype().commandSymbol() << std::endl;
std::cout << err_nickcollision(std::list<std::string>{}).getPrototype().commandSymbol() << std::endl;
std::cout << err_alreadyregistred(std::list<std::string>{}).getPrototype().commandSymbol() << std::endl;
std::cout << rpl_endofmotd(std::list<std::string>{}).getPrototype().commandSymbol() << std::endl;
std::cout << err_needmoreparams(std::list<std::string>{}).getPrototype().commandSymbol() << std::endl;
这种解决方法显然不是很实用,但它让我相信该错误与在这种情况下仅使用这些类型的静态方法有关;似乎模板已实例化,因此编译器会意识到该getPrototype
调用,但不会为其生成代码(导致“从未定义”的错误位)。
下面是一个成功使用getPrototype()
(这次, on numeric_base
) 的例子,它伴随着numeric_base
另一个翻译单元中的课程:
bool numeric_base::operator==(const numeric_base& other) const {
return getPrototype() == other.getPrototype() && m_args == other.m_args;
}
同样,这是在没有提到任何特定数字类型的地方,所以它没有什么可抱怨的。
的定义numeric_impl
如下:
template <const char* NumericCode, const char* SymbolicName, int NumArgs>
class numeric_impl : public numeric_base {
public:
template <typename Container>
numeric_impl(Container const& args) : numeric_base(args) {}
std::string serialize() const override {
// omitted
};
prototype getPrototype() const override { return s_prototype; }
static prototype Prototype() { return s_prototype; }
protected:
static const prototype s_prototype;
};
template <const char* NumericCode, const char* SymbolicName, int NumArgs>
const prototype numeric_impl<NumericCode, SymbolicName, NumArgs>::s_prototype = {NumericCode, SymbolicName, NumArgs, 0,
false};
忽略警告很简单,但我觉得这里正在发生更阴险的事情。更不用说更深入地了解编译器在这里的想法肯定会很好。任何见解将不胜感激。
解决方案
推荐阅读
- apache-spark - Hadoop/Spark:复制因子和性能有什么关系?
- java - BufferedReader 不返回
- javascript - 复选框上的表格行颜色更改以及从 MySQL 中选择时
- css - 如何在物化 css materialbox 中使用用户选项
- scala - 从 Akka Http 中的源向元素发送元素
- python - 在 Python 中迭代函数的参数(使用 2d numpy 数组和小数列表)
- maven - 使用没有 pom 文件的 maven repo
- mongodb - mongodb 副本集成员无法通过 SSL 加入集群
- mongodb - Mongo查询,分组数组条目
- php - Paypal PHP API SDK - 为购买人设置电子邮件地址