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)
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;
}
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
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
?
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)
答案 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.