一个 TU 中的模板专业化被另一个 TU 隐藏

Template specialisation in one TU hidden by another TU

我有一个 class 模板 可以 specialised 以改变用户定义的效用函数的行为类型。

我有一个使用效用函数的翻译单元我的类型的专业可用。使用专业化。

在一个单独的翻译单元中,如果我在不包括专业化的情况下调用效用函数,它会改变另一个 TU 的行为(专业化在 both TU)

这是描述我的问题的完整示例:

check.h: 定义了class模板,它可以专门用于用户定义的类型

#pragma once
#include <iostream>

template<typename T>
struct Check
{
    static void type();
};

template<typename T>
void Check<T>::type()
{
    std::cout << "check fall-back\n";
}

template<typename T>
void check(T&&)
{
    Check<T>::type();
}

type.h: 我自定义类型的定义

#pragma once

enum Foo
{
    FOO,
    BAR
};

type_check.h: 专攻 Check Foo

#pragma once
#include "type.h"
#include "check.h"

template<>
struct Check<Foo>
{
    static void type()
    {
        std::cout << "check Foo\n";
    }
};

lib.h: TU头文件

#pragma once

void lib();

lib.cpp: TU 源文件 - 使用来自 type_check.h

的专业化
#include "lib.h"
#include "type_check.h"

void lib()
{
    check(FOO);
}

main.cpp:

#include "check.h"
#include "type.h"
#include "lib.h"
#include "type_check.h" // uncomment this to make specialisation avail to all

int main()
{
    check(5);
    lib();
//  check(FOO); // uncomment this to change behaviour of lib()`
    return 0;
}

结果:

main 中调用 lib() 而不调用 check(FOO) 结果如下:

check fall-back
check Foo

main 中调用 lib()check(FOO) 结果如下:

check fall-back
check fall-back <-- main changes behaviour of lib
check fall-back

main.cpp 中包含 type_check.h,然后在 main 中调用 lib()check(FOO) 结果如下:

check fall-back
check Foo
check Foo

问题:

为什么在 Check<Foo> 专业化不可用时在单独的 TU 中调用 check(FOO) 将其从 lib.cpp 中的重载集中删除?

备注:

我不能只将 Check<Foo> 特化与 Foo 的定义放在同一个文件中,因为 Foo 实际上是一个生成的文件 (protobuf)

这违反了单一定义规则。链接器看到同一个函数的两个函数定义,并会选择一个。不需要诊断。

在这种情况下,void Check<Foo>::type 由 lib.cpp 中使用的 check.h 模板定义的实例化定义一次,而另一个定义来自 type_check.h用于 main.cpp.