c++ - 在多个文件之间拆分模板特化会导致 ODR 违规吗?
问题描述
我编写了一个解析器类,其中包含其他特定类型解析器的基本功能。例如,它包含一个从字符串创建枚举值的函数。
我不希望基类包含有关特定类型的信息,因此我将其实现为模板并使用 trait 来避免包含特定类型的标头:
// ParserBase.h
#include "EnumTrait.h"
template<typename EnumT>
EnumT parseEnum(std::string str)
{
return traits::EnumTrait<EnumT>::fromString(str);
}
EnumTrait
模板定义如下:
// EnumTrait.h
namespace traits
{
template<typename T>
struct EnumTrait
{
static_assert(sizeof(T) == -1, "Specialization not found");
};
} // namespace traits
现在,在定义我的枚举的每个标头中,也有此模板的特化。例如:
// Enum_A.h
#include "EnumTrait.h"
namespace A
{
enum class Enum_A
{
A
};
Enum_A fromString(std::string) {return Enum_A::A;}
} // namespace A
namespace traits
{
template<>
struct EnumTrait<A::Enum_A>
{
static std::string fromString(std::string str){ return A::fromString(str); }
};
// namespace traits
其他枚举的标头看起来相似。
基函数的使用:
// Enum_AParser.cpp
#include "ParserBase.h"
#include "Enum_A.h"
// ...
Enum_A foo = parseEnum<Enum_A>(bar);
// ...
我担心的是:这(是否)会导致违反 ODR(或其他一些问题)?
不可能使用 traitEnum_A
并且没有可用的特化,因为它们是在同一个标头中定义的。
但是,在使用模板的每个 TU 中都没有可用的每个模板特化是否可以(例如 Enum_A 在 Enum_BParser 中不可用)?
考虑到这一点时我注意到的一件事是,在标准库中创建我们自己的模板专业化是合法的,所以也许它毕竟是可以的?
我正在使用 C++17,如果这有什么改变的话。
解决方案
对我来说看起来不错。不需要每个专业化在每个翻译单元中都可见。只需要在每次使用模板之前声明特化,否则会触发隐式实例化。
[temp.expl.spec]/7如果模板、成员模板或类模板的成员被显式特化,则应在第一次使用该特化之前声明该特化,这将导致发生隐式实例化,在发生这种使用的每个翻译单元;不需要诊断...
推荐阅读
- android - 约束布局不约束其他布局的嵌套元素
- spring - 将 Spring 配置文件扩展名 .properties 更改为其他内容
- c - 从文件中读取 N 个字节并使用 read() 和 write() 打印它
- c# - 排序后向数据表添加排名列
- angular - --prod 升级到 Angular 7 后生成警告和部署的应用程序未加载
- r - ggplot2:将标签添加到 geom_bar() 以进行计数
- android - show() 方法使工厂眨眼
- java - 将 EntrySet 的流收集到 LinkedHashMap
- c# - 动态添加字典中的键
- go - 执行 goroutine 时的并发性与并行性