【问题标题】:Why specializing a template in source file does not cause an error?为什么在源文件中专门化模板不会导致错误?
【发布时间】:2019-09-24 15:58:59
【问题描述】:

在查看工作中的一些代码时,我注意到一些我认为不应该编译的东西,但令我惊讶的是,它可以编译。

头文件中定义了一个模板函数:

template <class T>
web::json::value get_key(const web::json::value &json, const utility::string_t &key) {
    return json.has_field(key) ? json.at(key) : web::json::value(T());
}

在源文件中具有特化:

template <>
web::json::value get_key<utility::string_t>(const web::json::value &json, const utility::string_t &key) {
    return json.has_string_field(key) ? json.at(key) : web::json::value(utility::string_t());
}

编辑:头文件中没有声明特化。

据我所知,这应该会导致编译器为get_key&lt;utility::string_t&gt; 发出两种不同的定义,一种用于源文件中的特化,另一种是在主模板被实例化时违反 ODR。但是,g++ 8.3.1 编译和链接这个没有任何错误。

谁能解释一下这里发生了什么?我是否遗漏了什么,上面的代码实际上是有效的,或者这只是一种未定义的行为?

谢谢!

【问题讨论】:

  • 只有在源令牌不同时才违反 ODR。在这种情况下,我相信它们会是一样的。
  • 如果您从未在其他源文件中使用utility::string_t 版本,则不会违反 ODR,因为只有一个定义。
  • @RichardCritten 你有has_fieldhas_string_field 所以这些是不同的。
  • @Holt 好点
  • 可以允许您跟进多个定义,您需要通过项目符号点:en.cppreference.com/w/cpp/language/definition

标签: c++ templates g++ one-definition-rule


【解决方案1】:

没有违反 ODR。当需要特化时,只应在首次使用函数模板之前声明特化并使其可见。

【讨论】:

  • 即使你没有声明特化,它也不会导致 gcc 出现任何错误......我不知道这是否是标准行为。
  • @Holt 你的意思是在调用特化之后才声明特化?
  • @VladfromMoscow 我的意思是在我调用它时甚至没有声明专业化(仅定义了模板)。专业化在不同的源文件中定义。查看程序集时,该函数在两个程序集文件中都定义了,但是在编译和链接时,一切顺利,并且从主文件中调用了特化。
  • @Holt 如果调用了专门化但尚未声明(在调用后声明),则程序格式错误。允许编译器不发出错误。
  • @VladfromMoscow 在这种情况下,除了定义的地方之外,没有在任何地方声明特化,并且用objdump检查文件表明在与源文件相对应的目标文件中发出了不同的目标代码,并在与包含标头的其他源文件相对应的目标文件中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 2013-06-22
  • 2018-11-16
  • 1970-01-01
  • 2013-03-21
相关资源
最近更新 更多