I am referring to this answer:
https://stackoverflow.com/a/4447057/930315
I ran into a similar issue as the OP of the cited question,
having a function
template<typename T>
void func(T& val);
and its specialization
template<>
void func<mytype>(mytype& val);
resulted in a duplicate symbols linker error (the methods are implemented in a '.tpp' file that is included at the end of my header).
adding inline to the specialised function resolved the issue. Why?
Well, if you want the standard quote on this, that'd be over at [temp.expl.spec]/12
An explicit specialization of a function or variable template is
inline only if it is declared with the inline specifier or defined as
deleted, and independently of whether its function or variable
template is inline. [ Example:
template<class T> void f(T) { /* ... */ }
template<class T> inline T g(T) { /* ... */ }
template<> inline void f<>(int) { /* ... */ } // OK: inline
template<> int g<>(int) { /* ... */ } // OK: not inline
— end example ]
That's why you have to do it. It's independent because I believe doing otherwise would be needlessly restrictive, as Yola demonstrated.
This will work without inline:
file1.h
template<typename T> void func(T& val);
template<> void func<mytype>(mytype& val);
file1.cpp
template<> void func<int>(int& ) {}
But if you define template specialization in header file, than you may violate ODR
According to clause 3.2:4 in the c++ standard
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program; no diagnostic
required. The definition can appear explicitly in the program, it can
be found in the standard or a user-defined library, or (when
appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.
This explains why there is a link-time error when the specialized function is not declared inline. The program will contain multiple definitions of the specialized function, one from each module including the .tpp-file and this breaks the condition from the standard. When declaring the specialized function inline it will make the function satisfy the second part of the same clause, i.e. that an inline function must be defined in each module using the function.
When the parameterized function is not specialized it is covered by clause 3.2:6:
There can be more than one definition of a class type (Clause 9),
enumeration type (7.2), inline function with external linkage (7.1.2),
class template (Clause 14), non-static function template (14.5.6),
static data member of a class template (14.5.1.3), member function of
a class template (14.5.1.1), or template specialization for which some
template parameters are not specified (14.7, 14.5.5) in a program
provided that each definition appears in a different translation unit
This clause states that it is OK for multiple definitions of the same template function as long as at least one of the template parameters is not specified in the code. This is to allow the decision on whether the parameterized function should be instantiated in a module to be made on local information only.
Related
//Tpl.h
template<typename T>
void show(T){
}
// a translate unit
#include "Tpl.h"
void h(){
show(0); //implicitly instantiate specialization for show<int>
}
// b translate unit
#include "Tpl.h"
int main(){
show(0); //implicitly instantiate specialization for show<int>
}
According to rules in [temp.inst], there is a specialization for function template show in a and b translate unit respectively, that means there're two same specializations in a program.
However, the ODR rule does not mention this case.
basic.def.odr#6
There can be more than one definition of a class type, enumeration type, inline function with external linkage ([dcl.inline]), inline variable with external linkage ([dcl.inline]), class template, non-static function template, static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
The case the rule listed are the following:
class type
enumeration type
inline function or inline variable
class template
non-static function template
static data member of a class template
member function of a class template
template specialization for which some template parameters are not specified
So, how about function template or static member function template ?
It also doesn't cover the case that exists more than one same specializations for a template in a program, the last item in the above list seems to refer to template partial specializations, So Is it a defect? Or there're other special rules applied to this case?
I am referring to this answer:
https://stackoverflow.com/a/4447057/930315
I ran into a similar issue as the OP of the cited question,
having a function
template<typename T>
void func(T& val);
and its specialization
template<>
void func<mytype>(mytype& val);
resulted in a duplicate symbols linker error (the methods are implemented in a '.tpp' file that is included at the end of my header).
adding inline to the specialised function resolved the issue. Why?
Well, if you want the standard quote on this, that'd be over at [temp.expl.spec]/12
An explicit specialization of a function or variable template is
inline only if it is declared with the inline specifier or defined as
deleted, and independently of whether its function or variable
template is inline. [ Example:
template<class T> void f(T) { /* ... */ }
template<class T> inline T g(T) { /* ... */ }
template<> inline void f<>(int) { /* ... */ } // OK: inline
template<> int g<>(int) { /* ... */ } // OK: not inline
— end example ]
That's why you have to do it. It's independent because I believe doing otherwise would be needlessly restrictive, as Yola demonstrated.
This will work without inline:
file1.h
template<typename T> void func(T& val);
template<> void func<mytype>(mytype& val);
file1.cpp
template<> void func<int>(int& ) {}
But if you define template specialization in header file, than you may violate ODR
According to clause 3.2:4 in the c++ standard
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program; no diagnostic
required. The definition can appear explicitly in the program, it can
be found in the standard or a user-defined library, or (when
appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.
This explains why there is a link-time error when the specialized function is not declared inline. The program will contain multiple definitions of the specialized function, one from each module including the .tpp-file and this breaks the condition from the standard. When declaring the specialized function inline it will make the function satisfy the second part of the same clause, i.e. that an inline function must be defined in each module using the function.
When the parameterized function is not specialized it is covered by clause 3.2:6:
There can be more than one definition of a class type (Clause 9),
enumeration type (7.2), inline function with external linkage (7.1.2),
class template (Clause 14), non-static function template (14.5.6),
static data member of a class template (14.5.1.3), member function of
a class template (14.5.1.1), or template specialization for which some
template parameters are not specified (14.7, 14.5.5) in a program
provided that each definition appears in a different translation unit
This clause states that it is OK for multiple definitions of the same template function as long as at least one of the template parameters is not specified in the code. This is to allow the decision on whether the parameterized function should be instantiated in a module to be made on local information only.
I just wanted to know:
Is it ok to declare a template function (not a member function) in a header such as:
template<class I>
inline I f(const cv::Mat & inMat)
{
throw(std::logic_error("No override found for this type of image"));
}
And then, define what is allowed in the cpp file like this:
template<>
ImageRgbT f<ImageRgbT>(const cv::Mat & inMat)
{
}
I'm trying not to use a specialized class.
You need to declare your specialization in the header:
template<>
ImageRgbT f<ImageRgbT>(const cv::Mat & inMat);
Otherwise, your program is ill-formed NDR according to [temp.expl.spec]/6:
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.
Violating this rule can cause the compiler to emit one definition for f<ImageRgbT> in one translation unit, instantiated from the primary template, and a different one in the translation unit containing the explicit specialization, leading to linker trouble. It only appears to work in your case because you got lucky and because no diagnostic is required.
Provided that the specialization is declared in the header, there is no problem with defining it in a separate file.
I just read that constexpr and inline functions obey one-definition rule, but they definition must be identical. So I try it:
inline void foo() {
return;
}
inline void foo() {
return;
}
int main() {
foo();
};
error: redefinition of 'void foo()',
and
constexpr int foo() {
return 1;
}
constexpr int foo() {
return 1;
}
int main() {
constexpr x = foo();
};
error: redefinition of 'constexpr int foo()'
So what exactly means that, constexpr and inline function can obey ODR?
I just read that constexpr and inline functions obey one-definition rule, but they definition must be identical.
This is in reference to inline functions in different translations units. In your example they are both in the same translation unit.
This is covered in the draft C++ standard 3.2 One definition rule [basic.def.odr] which says:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements. Given
such an entity named D defined in more than one translation unit, then
and includes the following bullet:
each definition of D shall consist of the same sequence of tokens; and
You are defining functions repeatedly in one translation unit. This is always forbidden:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration
type, or template. (C++11 3.2/1)
For inline functions, you are allowed to define same function in exactly the same way in more than one translation unit (read: .cpp file). In fact, you must define it in every translation unit (which is usually done by defining it in a header file):
An inline function shall be defined in every translation unit in which it is odr-used. (C++11 3.2/3)
For "normal" (non-inline, non-constexpr, non-template, etc.) functions with external linkage (non-static) functions, this will usually (no diagnostic required) lead to a linker error.
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. (C++11 3.2/3)
To sum up:
Never define anything multiple times in one translation unit (which is a .cpp file and all directly or indirectly included headers).
You may put a certain number of things into header files, where they will be included once in several different translation units, for example:
inline functions
class types and templates
static data members of a class template.
If you have:
file1.cpp:
inline void foo() { std::cout << "Came to foo in file1.cpp" << std::endl; }
and
file2.cpp:
inline void foo() { std::cout << "Came to foo in file2.cpp" << std::endl; }
and you link those files together in an executable, you are violating the one-definition-rule since the two versions of the inline function are not same.
I'm specializing member functions of a template class in a header file like so:
#pragma once
#include <iostream>
template<class T>
struct Test
{
void Print() { }
};
template<>
void Test<int>::Print()
{
std::cout << "int" << std::endl;
}
Is it correct to put the specialization in a header file (without it being inline), or should it be in a cpp file? It compiles fine as shown above (using VS2012), but I'm rather surprised I don't get multiple definition linker errors.
The ODR requires exactly one definition for non-inline functions that are ODR-used (that roughy means, for functions, being potentially called).
Quoting n3485, [basic.def.odr]
4 Every program shall contain exactly one definition of
every non-inline function or variable that is odr-used in that
program; no diagnostic required.
Then, there's an exception for templates (i.e. not for functions):
6 There can be more than one definition of a class type [...], class template, non-static function template, static data member
of a class template, member function of a class template, or template specialization for
which some template parameters are not specified in a program provided that [...]
[emphasis mine]
An explicit specialization of a template is not a template. For example, an explicitly specialized class template is a class (with a strange name). Therefore, your assumption is correct and multiple definitions for explicitly specialized members of class templates violate the ODR.
With g++4.8.1, I even get a linker error in such a program; note that I have ODR-used the function. No diagnostic is required for a violation of the ODR.
Putting the specialisation in the header file is the canonical form (as boost does), it doesn't violate the ODR.