未解析的 NON 模板方法正在被正确实例化的模板方法调用

Unresolved NON template method being called by template method which is correctly instantiated

提问人:Fabio A. 提问时间:12/2/2015 最后编辑:Fabio A. 更新时间:12/3/2015 访问量:66

问:

在决定问这个问题之前,我搜索了整个互联网和堆栈溢出,所以如果我忽略了一些非常简单的事情,请原谅,但事实就是如此。

使用 Visual Studio 2010,我有一个这样的类:

class MyClass {
public:
    /* Constructors and other methods omitted */

    template <typename T1>
    CString operator()(const T1 &a1) { return _fmt("dummy", a1); }

    template <typename T1, typename T2>
    CString operator()(const T1 &a1, const T2 &a2) { return _fmt("dummy", a1, a2); }

    template <typename T1, typename T2, typename T3>
    CString operator()(const T1 &a1, const T2 &a2, const T3 &a3) { return _fmt("dummy", a1, a2, a3); }

    template <typename T1, typename T2, typename T3, typename T4>
    CString operator()(const T1 &a1, const T2 &a2, const T3 &a3, const T4 &a4) { return _fmt("dummy", a1, a2, a3, a4); }

private:    
    CString _fmt(const char *dummy, ...);
};

这个想法是为 MyClass 提供一个重载,其作用类似于 sprintf() 格式化程序,只是格式字符串包含在 MyClass 实例本身中。我会使用可变参数模板,唉 Visual Studio 2010 不支持它们,因此半生不熟的解决方案是提供许多重载模板版本,这些模板版本反过来都调用一个私有函数,该函数使用并因此强制需要无用的第一个参数(因此得名“虚拟”)。operator ()operator ()_fmt()va_list/va_start()/va_end()

编译进行得很好,但是链接会给出如下错误:

error LNK2019: unresolved external symbol "private: class ATL::CStringT<char,class ATL::StrTraitATL<char,class ATL::ChTraitsCRT<char> > > __cdecl MyClass::_fmt(char const *,...)" (?_fmt@MyClass@@AAA?AV?$CStringT@DV?$StrTraitATL@DV?$ChTraitsCRT@D@ATL@@@ATL@@@ATL@@PBDZZ) referenced in function "public: class ATL::CStringT<char,class ATL::StrTraitATL<char,class ATL::ChTraitsCRT<char> > > __thiscall MyClass::operator()<char [261]>(char const (&)[261])" (??$?R$$BY0BAF@D@MyClass@@QAE?AV?$CStringT@DV?$StrTraitATL@DV?$ChTraitsCRT@D@ATL@@@ATL@@@ATL@@AAY0BAF@$$CBD@Z)

我从上面的消息中了解到,模板化运算符已正确实例化,并且它包含对方法的调用,但是,链接器无处可寻。_fmt()

但是包含在正在编译和喜欢的 .cpp 文件中,实际上构造函数也在那里定义,链接器不会抱怨它。_fmt()

我发现解决这个问题的唯一方法是将代码放在类定义正文的头文件中,这相当丑陋。_fmt()

有什么想法吗?

C++ Visual-Studio-2010 模板 未解析的外部

评论

0赞 R_Kapp 12/2/2015
我脑海中浮现的第一个也是最明显的想法是:在实现文件中,您是否将其定义为 而不是 ?除此之外,没有看到如何定义,我什么都没有。CString MyClass::_fmt(...)CString _fmt(...)_fmt
0赞 Fabio A. 12/3/2015
我做到了,我三重检查了一下。但是现在我已经仔细检查了错误,但有些东西没有加起来:使用的 CString 模板似乎使用了与有效编译的模板不同的特征类。在目标文件中,我得到一个符号,名称如下: 它解体为: 注意它如何使用而不是 .我猜标题不匹配。?_fmt@MyClass@@AAA?AV?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@PBDZZprivate: class ATL::CStringT<char,class StrTraitMFC<char,class ATL::ChTraitsCRT<char> > > __cdecl MyClass::_fmt(char const *,...)StrTraitMFCATL::StrTraitATL

答:

1赞 Fabio A. 12/3/2015 #1

好吧,这是一个愚蠢的问题,但由于其他人可能会以某种方式绊倒它,我正在回答我自己的问题。

我错误地包含了头文件,这是MFC的一部分,以便获取类定义,而项目的其余部分则使用ATL,这带来了不同版本的CString。然而,不知何故,这只影响了 MyClass 实现文件,而其他人,即使他们使用的是 MyClass,也得到了不同版本的 CString。<afxmt.h>CCriticalSection

我通过自己不包含和实现类来解决这个问题。<afxmt.h>CCriticalSection