首页 > 解决方案 > 如何修复成员函数上的“声明为'静态'但从未定义”?

问题描述

我正在实现一个 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()在此特定上下文中调用时才会发生上述呕吐。

现在,一些上下文:

触发错误的代码基本上如下:

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};

忽略警告很简单,但我觉得这里正在发生更阴险的事情。更不用说更深入地了解编译器在这里的想法肯定会很好。任何见解将不胜感激。

标签: c++

解决方案


推荐阅读