在多个文件之间拆分模板专业化会导致 ODR 违规吗?

Can splitting template specializations between multiple files lead to ODR violations?

我编写了一个解析器 class,其中包含其他类型特定解析器的基本功能。例如,它包含一个从字符串创建枚举值的函数。

我不希望基 class 包含有关特定类型的信息,因此我将其实现为模板并使用特征来避免包含特定类型 header:

// 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

现在,在定义我的枚举的每个 header 中,也有针对此模板的专门化。例如:

// 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

Headers 其他枚举看起来相似。

基函数的用法:

// Enum_AParser.cpp
#include "ParserBase.h"
#include "Enum_A.h"
// ...
Enum_A foo = parseEnum<Enum_A>(bar);
// ...

我担心的是:这(是否)会导致 ODR 违规(或其他一些问题)?

无法使用具有 Enum_A 的特性并且没有可用的特化,因为它们在相同的 header.

中定义

但是在使用模板的每个 TU 中不提供每个模板专业化是否可以(例如 Enum_A 在 Enum_BParser 中不可用)?

我在考虑这个问题时注意到的一件事是,在标准库中创建我们自己的可用模板专业化是合法的,所以也许这毕竟没问题?

我正在使用 C++17,如果它改变了什么。

我觉得不错。不要求每个专业化在每个翻译单元中都可见。只需要在每次使用模板之前声明特化,否则会触发隐式实例化。

[temp.expl.spec]/7 If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required...