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.
Related
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.
In this question, the accepted answer involves a template function declaration in a header file which has its definition in the source file. To make this template function also usable in other translation units, explicit template instantiations are made in the source file for each "allowed" usage. So far this appears to me as standard practice.
The answer however also recommends placing corresponding explicit template instantiation declarations in the header file. I have not seen this practice before and would like to know if this is required by the standard.
Here is a small example:
A.h
struct A
{
template<class T>
void g(T t);
};
A.cpp
#include "A.h"
template<class T>
void A::g(T t)
{ /* ... */ }
template void A::g(int); // Explicit instantiation of the definition.
main.cpp
#include "A.h"
int main()
{
A a;
a.g(0);
}
The wording in the standard does not make it clear to me whether the explicit instantiation of the declaration is also required. This seems to primarily concern the "the definition is never instantiated explicitly, an implicit instantiation in A.cpp is not guaranteed to be retained" case (not depicted), but I would appreciate clarification.
Are explicit template instantiation declarations required in the header when explicitly instantiating the definitions in the source file?
No. The rule is, from [temp]/10, emphasis mine:
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.
In your example, A::g<int> is implicitly instantiated in main.cpp but it is explicitly instantiated in "some translation unit" (A.cpp). The program is fine.
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'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've recently run into a situation while specializing templates that has made me uneasy:
foo.h:
template <class T>
void foo() {
std::cout << "This is the generic foo" << std::endl;
}
foo.cc:
#include "foo.h"
template <>
void foo<int>() {
std::cout << "This is foo<int>" << std::endl;
}
main.cc:
#include "foo.h"
int main() {
foo<int>();
}
So. I compile as follows:
g++ -c main.cc
g++ -c foo.cc
g++ -o main main.o foo.o
The output is "This is foo<int>". I like this output. But I'm worried that what I'm observing might be unique to gcc (I don't have access to other compilers so I can't check).
Here's what I think gcc is doing: When main.cc is compiled, I would expect it to emit the generic code for the foo call because it is not aware of the specialization in foo.cc. But by linking with foo.o, it uses the specialization instead because it has the same signature.
But is this bad to count on? I'm worried that other compilers (or maybe even different versions of gcc?) might mangle their signatures when they emit template code, in a way that linking with foo.o will not replace the generic action like I want it to. Is this a valid worry? I've read a lot of things that make me feel uneasy, but nothing that makes me feel confident about what is happening in my current situation.
I'm worried that what I'm observing might be unique to gcc (I don't have access to other compilers so I can't check).
You have good reasons to be worried: Your program is ill-formed, and the compiler is not even required to tell you!
Paragraph 14.7.3/6 of the C++11 Standard specifies:
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
Your specialization must be visible from the point of instantiation in order for the program to have consistent behavior. In your case, it isn't: you are relegating it in a file which is not included by other translation units.
Paragraph 14.7.3/7 Standard is quite explicit about what happens when you fail to do this:
The placement of explicit specialization declarations for function templates, class templates, member functions
of class templates, [...], can affect whether a program is
well-formed according to the relative positioning of the explicit specialization declarations and their points of
instantiation in the translation unit as specified above and below. When writing a specialization, be careful
about its location; or to make it compile will be such a trial as to kindle its self-immolation.
I guess the last sentence makes it clear.
Here, what you should do is to declare your intention to introduce an explicit specialization of your function template before any implicit instantiation of the primary template would occur. To do so, do the following:
foo.h
template <class T>
void foo() {
std::cout << "This is the generic foo" << std::endl;
}
template <> void foo<int>(); // Introduce a declaration of your
// explicit specialization right
// after you defined the primary
// template!
By introducing a declaration right after the definition of the primary template, you make sure that wherever the primary template is visible, it will be known that a full specialization for it exists, saving you from self-immolation.