【问题标题】:template specialization multiply defined symbols模板特化 多重定义符号
【发布时间】:2010-12-15 05:27:45
【问题描述】:

我知道我在这里遗漏了一些简单的东西,但我有一个我专门研究的类的模板化成员函数。

MyClass
{
    template<typename T> T GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s);
}

template<typename T>
T MyClass::GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s)
{
    throw std::runtime_error("Don't know how to convert " + ToString(v->GetString()));
}

template<>
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s)
{
    return v->GetInteger();
}

template<>
string MyClass::GetTFromVariable<string>(shared_ptr<TOtSimpleVariable> v, string s)
{
    return v->GetString();
}

// etc for other specialisations.

这是在我的头文件中定义的(应该是模板),但是当我去编译时,我得到了一堆多重定义的符号,一个典型的错误是:

     OtCustomZenith_logic.lib(PtPathOutput.obj) : error LNK2005: "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall MyClass::GetTFromVariable<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(class boost::shared_ptr<class TOtSimpleVariable>,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??$GetTFromVariable@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@CommandProperties@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$shared_ptr@VTOtSimpleVariable@@@boost@@V12@@Z) already defined in TableFareSystem_test.obj

我可以通过内联方法来修复它,但我认为这没有必要......我忘记了什么?

编辑:我正在使用 Visual Studio 2010

【问题讨论】:

  • 你用的是什么工具链?海合会?视觉的东西?如果是 GCC,构建和链接行是什么样的?

标签: c++ templates linker


【解决方案1】:

完整的专业化不再是模板。这是一个具体的功能。因此,它需要(隐式或显式)声明inline。最简单的方法是在返回类型规范之前添加该关键字。

也就是说,显示的代码与您的错误消息不对应。

您的错误消息涉及返回类型std::string,而不是返回类型int

【讨论】:

  • "你的错误信息是关于返回类型std::string,而不是返回类型int。" ...这意味着它正在使用第一个(通用)模板,该模板返回类型 T(在本例中为 std::string)。
  • @Mike:不,这意味着提供的代码与错误消息不匹配。我可以猜测 OP 有几个明确的专业,而不仅仅是一个,而且他选择了任意错误消息。但这只是一个猜测。我是说,当你寻求帮助时,尽量准确,不要引入无关的问题。
  • 谢谢@alf,你是对的,我已经更新了问题以更准确地反映问题。
【解决方案2】:

正如 Alf 所说,完整的专业化不再是模板。 但是,我不确定它 必须 内联定义。 您还应该能够拆分声明和定义。

即在您的标题中有:

template<> 
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s);

并且在实现中有:

template<>
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s)
{
    return v->GetInteger();
}

我还认为,按权利,模板化定义也应该明确内联(我一直这样做),但如果给定的编译器在为模板应用 ODR 时松懈,也不会太惊讶.我很想看看另有说明的标准参考。

【讨论】:

  • 我很抱歉措辞不准确。我只是在谈论 OP 的代码,因为它是/呈现的,在头文件中有定义。感谢您的澄清!干杯,
  • 将专业化从头文件移动到单个 .cpp 文件意味着需要编译和链接到 .obj 或 .lib 损害可用性。最好按照@alf 的建议保持它内联。因此,我对你的答案投了反对票。
【解决方案3】:

我建议您从代码中完全删除以下实现,这样如果 T 不是 int,编译器可以在编译时自身生成错误。错误的早期检测优于延迟检测(在运行时完成)。

template<typename T>
T MyClass::GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s)
{
    throw std::runtime_error("Don't know how to convert " + ToString(v->GetString()));
}

讨论这件事的主题/问题完全相同。请看这个:

Partial template specialization for specific type, c++

【讨论】:

  • 最好删除它会留下这个但使用 static_assert(false, "解释问题和解决方案")。这将帮助开发人员了解如果错误结果出现了什么问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多