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.
Related
The standard allows function templates to be instantiated after the enclosing namespace-scope declaration or at the end of the translation unit when they are referred to from a non-template context: [temp.point]/1
For a function template specialization, a member function template
specialization, or a specialization for a member function or static
data member of a class template, if the specialization is implicitly
instantiated because it is referenced from within another template
specialization and the context from which it is referenced depends on
a template parameter, the point of instantiation of the specialization
is the point of instantiation of the enclosing specialization.
Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that
refers to the specialization.
[temp.point]/8
A specialization for a function template, a member function template,
or of a member function or static data member of a class template may
have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any
such specialization that has a point of instantiation within the
translation unit, the end of the translation unit is also considered a
point of instantiation. A specialization for a class template has at
most one point of instantiation within a translation unit. A
specialization for any template may have points of instantiation in
multiple translation units. If two different points of instantiation
give a template specialization different meanings according to the
one-definition rule, the program is ill-formed, no diagnostic
required.
Now consider this minimal reproducible example:
#include <iostream>
#include <array>
struct A {};
std::array<char, 2> show(float, A)
{
std::cout << "2\n";
return {};
}
template<typename T>
struct Fun {
decltype(show(0, T{})) b;
};
template <typename T>
void func(T, int c = sizeof(Fun<T>{}.b))
{
show(0, T{});
std::cout << c << '\n';
}
int main()
{
func(A{});
}
char show(int, A)
{
std::cout << "1\n";
return {};
}
Both GCC and Clang output 1 2 (godbolt).
Here, the instantiation of func<A> (triggered in main) has two points of instantiation: one immediately after main (and thus before the second show) and another at the end of the translation unit. The first 1 indicates that the compilers to instantiate func<A> at the end of the translation unit. However, the default argument sizeof(Fun<T>{}.b) causes Fun<A> to be instantiated, and the second 2 suggests that Fun<A> is instantiated before the second show.
Now, the point of instantiation of default arguments is specified to be that of func<A>: [temp.point]/2
If a function template or member function of a class template is
called in a way which uses the definition of a default argument of
that function template or member function, the point of
instantiation of the default argument is the point of instantiation of
the function template or member function specialization.
Hmm ... This seems to suggest that the two numbers should be the same.
I feel I'm missing something here. Is there any detail that I happened to neglect? Or did I make mistakes?
As quoted in the question [temp.point]/8 says:
If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.
According to the one-definition rule two definitions are not the same if function call overload resolution of a name used in the definition will yield different entities defined outside the definition. ([basic.def.odr]/6.2)
Overload resolution of the two calls to show in func<A> and in Fun<A> will choose different function overloads depending on whether func<A>'s point of instantiation is immediately after main or at the end of the translation unit, both of which are allowed points of instantiation.
Therefore the program is ill-formed, no diagnostic required.
This question already has answers here:
Should I declare my function template specializations or is defining them enough?
(2 answers)
Is it safe to place definition of specialization of template member function (withOUT default body) in source file?
(3 answers)
Closed 2 years ago.
I'm working on a codebase which uses the following structure:
a.h:
template<int N> void f();
void b();
a.cpp:
#include "a.h"
template<> void f<1>() {}
int main()
{
b();
}
b.cpp:
#include "a.h"
void b()
{
f<1>();
}
The code appears to build and run correctly.
My question is: is this well-formed, or is it some kind of ill-formed NDR that happens to work?
If building with clang -Wundefined-func-template (this was enabled in my IDE's default settings for clang-tidy) then a warning is produced:
b.cpp:5:2: warning: instantiation of function 'f<1>' required here, but no definition is available [-Wundefined-func-template]
f<1>();
^
./a.h:1:22: note: forward declaration of template entity is here
template<int N> void f();
^
b.cpp:5:2: note: add an explicit instantiation declaration to suppress this warning if 'f<1>' is explicitly instantiated in another translation unit
f<1>();
^
But I am not sure whether to just disable the warning, or make some code change (other than moving the explicit specialization definition to the header file, which would not be preferable for this project).
Following the advice in the warning message and adding an explicit instantiation declaration to the header file (i.e. extern template void f<1>();) caused an error message (implicit instantiation of a specialization before explicit instantiation).
However, adding an explicit specialization declaration template<> void f<1>(); to the header file suppresses the warning. But I am not sure if this is (a) necessary, and/or (b) recommended style.
The program violates [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.
The function template f is explicitly specialized by template<> void f<1>() {} in b.cpp. But in the translation unit formed from b.cpp and including a.h, the statement f<1>(); would cause an implicit instantiation of the same specialization f<1>, and there is no declaration of the explicit specialization earlier (or anywhere) in the translation unit.
Per the Standard, an explicit specialization is always a distinct thing from an instantiated specialization, since both can never exist for the same primary template and same template arguments. But the program might work anyway because many compilers use the same mangled linker names for template explicit specializations and instantiated specializations.
The clang warning might be because it's legal, though unusual, to implicitly instantiate a function template without a visible definition if the same specialization is explicitly instantiated, not explicitly specialized, elsewhere. So it's suggesting an improvement to make a legal program clearer. I'm not exactly sure if it actually is legal, though. But its suggested explicit instantiation declaration would be a lie, since the specialization is explicitly specialized, not explicitly instantiated.
The program does become valid if you add explicit specialization declarations to the header file for every specialization which will be used.
template<int N> void f();
template<> void f<1>();
There's an example in [temp.over]/5 that matches yours almost exactly, and pronounces it well-formed:
[temp.over]/5 ... [ Example:
template<class T> void f(T); // declaration
void g() {
f("Annemarie"); // call of f<const char*>
}
The call of f is well-formed even if the template f is only declared and not defined at the point of the call. The program will be ill-formed unless a specialization for f<const char*>, either implicitly or explicitly generated, is present in some translation unit. —end example ]
[temp]/7 says:
A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated unless the corresponding specialization is explicitly instantiated in some translation unit; no diagnostic is required.
The standard requires explicit instantiation, so explicit specialization in a.cpp won't make the program well-formed.
A similar question ([temp]/7 treats function templates and member functions of class templates equally) was asked in CWG2138:
It is not clear whether the following common practice is valid by the current rules:
// foo.h
template<typename T> struct X {
int f(); // never defined
};
// foo.cc
#include "foo.h"
template<> int X<int>::f() { return 123; }
// main.cc
#include "foo.h"
int main() { return X<int>().f(); }
which was closed as NAD with the following rationale:
As stated in the analysis [which referred to [temp]/7, among other things], the intent is for the example to be ill-formed, no diagnostic required.
So, the answer is: the program is ill-formed NDR, and this is intended.
According to [temp.spec]/5:
For a given template and a given set of template-arguments,
...
an explicit specialization shall be defined at most once in a program (according to [basic.def.odr]), and
...
the definition of an explicit (full) specialization of a class template cannot be placed in a header (otherwise there is one definition in each translation unit containing this header, thus there will be more than one definition in the whole program).
In addition, as another evidence, the entities listed in [basic.def.odr]/12 (blockquoted below) do not contain a full specialization of a class template. Instead, "template specialization for which some template parameters are not specified" is contained.
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, concept ([temp.concept]), 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.
However, if I place the definition in a source file and leave its declaration in a header, for example,
// "a.h"
template <typename T>
struct S {};
template <>
struct S<int>; // declaration
// "a.cpp"
#include "a.h"
template <>
struct S<int> {}; // definition
// "main.cpp"
#include "a.h"
int main()
{
S<int> s;
}
then an error occurs (tested by gcc) because S<int> is an incomplete type.
In conclusion, where should I place the definition of an explicit specialization of a class template?
I am going to try to summarize here what I've learned through the discussion in my other answer, in the hopes of leaving a good answer to this question, rather than having the answer be buried in the comments.
The standard says
an explicit specialization shall be defined at most once in a program (according to ODR)
ODR is the One Definition Rule. You can only define each class once within a program, with an exception designed to allow a class definition to be available in each translation unit: you can define a class in different translation units as long as these different definitions are identical, character for character. The quote of the OP is part of the ODR description, follow the OP's link to see the full description.
So IMO the standard's text above means that an explicit specialization can be defined only once, but according to the ODR, and thus with the same exceptions: you can define it in a header file so it is available in multiple translation units.
Note that it is not possible to instantiate a class without its full definition (the compiler needs to know at least how many bytes to allocate for it). The same is true for a templated class, or a specialization of such a class. So it must be possible for the definition to be present in each translation unit that uses it.
This is a definition (the specialization will be instantiated), not a declaration, it probably ought to go in a specific source file (*.cpp):
template <> struct S<int>;
Note: it doesn't "hurt" to have this in every translation unit... other than the time it takes to instantiate by the compiler, and the bloat for the object files (*.o or *.obj).
This is a declaration (the specialization will not be instantiated), and is okay to put in a header file (*.h):
extern template <> struct S<int>;
The declaration requires C++11 or later.
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.
I have a template class that I declare in a header with one method and no definition of that method in the header. In a .cc file, I define specializations of that method without ever declaring them in the header. In a different .cc file, I call the method for different template parameters for which specializations exist. It looks like this:
foo.h:
template<typename T>
class Foo {
public:
static int bar();
};
foo.cc:
#include "foo.h"
template<>
int Foo<int>::bar() {
return 1;
}
template<>
int Foo<double>::bar() {
return 2;
}
main.cc:
#include <iostream>
#include "foo.h"
int main(int argc, char **argv) {
std::cout << Foo<int>::bar() << std::endl;
std::cout << Foo<double>::bar() << std::endl;
return 0;
}
This program compiles and links successfully with gcc 4.7.2 for all C++ standards (c++98, gnu++98, c++11, and gnu++11). The output is:
1
2
This makes sense to me. Because the main.cc translation unit does not see a definition of bar() or any specializations of it, it expects the calls to bar() to use explicit instantiations of an unspecialized definition of bar() in some other translation unit. But since name mangling is predictable, the specializations in foo.cc have the same symbol names as explicit instantiations of an unspecialized definition would, so main.cc is able to use those specializations without them ever being declared in that translation unit.
My question is this: is this an accident, or is this behaviour mandated by the C++ standard? In other words, is this code portable?
The most relevant prior question that I could find is Declaration of template class member specialization, but it doesn't cover this particular case.
(In case you're wondering why this matters to me, it's because I'm using code like this as a sort of compile-time look-up table and it's a lot shorter if I don't declare the specializations.)
The Standard (C++11) requires that explicit specializations be declared (but not necessarily defined) before they are first used:
(14.7.3/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. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the
program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. [...]
I believe that this will in practice only have an effect when your primary template definition includes the definition of the non-specialized version of one of the member functions. Because in that case, when the explicit specialization isn't declared, the existing primary definition may be used to compile the function inline into the code, and the specialization would end up not being used at link-time.
In other words, if there is no definition of the member function included in the primary template definition, your linker trick can probably be expected to work in practice, but it wouldn't conform with what the Standard says, and it can get you into real trouble as soon as you add an inline function definition to the primary template.