Template specialisation in one TU hidden by another TU

时间:2015-09-29 00:41:29

标签: c++ templates template-specialization

I have a class template which can be specialised in order to change behaviour of a utility function for user defined types.

I have one translation unit which uses the utility function with my type's specialisation available. The specialisation is used.

In a separate translation unit, if I call the utility function without including the specialisation, it changes the behaviour of the other TU (the specialisation is not used in both TUs)

Here is a complete example describing my issue:

check.h: defines the class template which can be specialised for user defined types

#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: definition of my user-defined type

#pragma once

enum Foo
{
    FOO,
    BAR
};

type_check.h: specialises Check for Foo

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

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

lib.h: TU header file

#pragma once

void lib();

lib.cpp: TU source file - uses the specialisation from 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;
}

Results:

Calling lib() without calling check(FOO) in main results in the following:

check fall-back
check Foo

Calling lib() and check(FOO) in main results in the following:

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

Including type_check.h in main.cpp, and then calling lib() and check(FOO) in main results in the following:

check fall-back
check Foo
check Foo

Question:

Why does calling check(FOO) in a separate TU when the Check<Foo> specialisation is not available remove it from the overload set in lib.cpp?

Notes:

I can't just put the Check<Foo> specialisation in the same file as the definition of Foo, as Foo is actually a generated file (protobuf)

1 个答案:

答案 0 :(得分:2)

This is a violation of the One Definition Rule. The linker sees two function definitions for the same function and will pick one. No diagnostic is required.

In this case, void Check<Foo>::type is defined once by the instantiation of the template definition from check.h used in lib.cpp, while the other definition is from type_check.h used in main.cpp.