template specialization, different behavior on windows vs gcc? - c++

I'm looking for an overview or description of what GCC does differently than MSVC for compile + link of template classes with specializations. For example, this type of thing works on GCC but not MSVC:
// Base.h
template <typename T> struct Base {
template <class G> QString makeTitle(const G* obj){obj->CompilerError();}
};
// in Foo.cpp
template <> template <class G> QString Base<T_1>::makeTitle(const G* obj) { return mystr(); }
void SomeFunc() {
std::cout<< Base<T_1>().makeTitle<myclass>() ;
}
and the solution tends to be that I must declare the specialization in Base.h before using it, or on windows there is a link error. How/why does MSVC implicitly instantiate differently, and how/why is GCC robust to the specialization being declared in some cpp file?
related question that notes the general 'declare before using' requirement: Template specialization - different behaviour between MSVC and GCC/MinGW

The first thing is that your code is in violation of the ODR rule if any translation unit includes the header and causes the definition of the specialization without the compiler seeing a declaration. Since that is undefined behavior the fact that one compiler accepts it and the other rejects it is well within reason.
The correct code, as you already figured out is to provide the declaration of the specialization, and that will work in any compiler.
As of why it seems to work or even why does it actually work in gcc, this is most probably a matter of how the code is generated and the linker processes the object files. In particular in gcc the compiler will generate the specialization in the translation unit that needs it (and does not see your own specialization), but it will be marked as a weak symbol. The gcc linker will accept a symbol being multiply defined if all but [at most] one definitions are weak, leaving the strong symbol in the final executable.

Related

Why does explicit template instantiation result in weak-template-vtables warning when there are out-of-line virtuals?

[Edited to show split between .cpp and hpp]
// file.hpp
class Base {
public:
virtual ~Base(void);
Base(void);
Base(const Base&) = default;
};
template<typename T>
class Derived: public Base {
public:
Derived(void);
bool func(void);
};
// file.cpp
#include "file.hpp"
Base::~Base(void) {}
Base::Base(void) {}
template<typename T>
bool Derived<T>::func(void) {return true;}
template<typename T>
Derived<T>::Derived(void) {}
// required to avoid linker errors when using `Derived` elsewhere
template class Derived<int>;
The last line causes the following compiler warning in Clang v8.0 warning: explicit template instantiation 'Derived<int>' will emit a vtable in every translation unit [-Wweak-template-vtables]
My understanding is that because Base has at least one out-of-line virtual method, the vtables for all classes here would be anchored to this translation unit, hence this guidance in the LLVM coding standard. So why is this warning being generated?
See on Godbolt here with specific compiler version I'm using: https://godbolt.org/z/Kus4bq
Every similar question I find on SO is for classes with no out-of-line virtual methods so I have not been able to find an answer.
EDIT: I do not think this is a bug in Clang, but instead a consequence of a requirement of the Itanium C++ ABI: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vague-itemplate This section is referenced in the Clang source in RecordLayoutBuilder.cpp in computeKeyFunction:
Template instantiations don't have key functions per Itanium C++ ABI 5.2.6. Same behaviour as GCC.
The Itanium specification says that class template instantiations will be stored in a COMDAT section in the object file. COMDAT sections are used to store multiple definitions of the same object, which can then be unified at link-time. If the template was compiled the way I expected in my answer, with a key function anchoring it to a specific translation unit, then that wouldn't be compliant with this ABI.
I do think the warning is unhelpful, but as it's not part of -Wall or -Wextra I don't mind so much.
(Original post below)
I'm inclined to believe that this is due to a bug in Clang, reported here: https://bugs.llvm.org/show_bug.cgi?id=18733
Reposting content here in case the link breaks:
Rafael Ávila de Espíndola 2014-02-05 00:00:19 PST
Given
template<typename T>
class foo {
virtual ~foo() {}
};
extern template class foo<int>;
template class foo<int>;
clang warns:
test.cpp:6:23: warning: explicit template instantiation 'foo<int>' will emit a vtable in every translation unit [-Wweak-template-vtables]
extern template class foo<int>;
^
1 warning generated.
note that the warning points to the explicit template instantiation declaration, but is triggered by the definition. This should probably be checking if the definition is in a header. In a .cpp file there is only one translation unit that sees it.
Comment 1 David Faure 2016-02-13 12:21:27 PST
Yes, this false positive is indeed annoying. Thanks for reporting it. Clang developers: thanks for fixing it :-)
I'd be grateful for anyone else's opinion, but I agree with the bug reporter that this warning seems bogus in this case.
Although the last comment on the bug report refers to it as fixed, the bug is still listed with status "new", so I do not believe it is fixed.
Does the line template class Derived<int>; exist in a header-file, which again is included in multiple source-files?
In that case the, vtable and methods of class Derived<int> will exist in multiple object-files. And the linker has to figure out what to do with those multiple copies.
How the compiler and linker is supposed resolve this according to the c++ standard, i am not sure of. But typically I don't care since the copies should normally look the same.
But to avoid this issue, you should put extern template class Derived<int>; in the header file, and template class Derived<int>; in exactly 1 compile unit (aka. source-file)
EDIT (to reflect your split of the code into "file.hpp" and "file.cpp"):
I have played a little bit with clang-6 (I that is the latest version I have)
To me the warning is of the type "If you do X, Y will happen". But it doesn't mean y has happened.
In this case Y is multiple vtables and that will only happen if you put template class Derived<int>; in multiple source files, which you dont't do.
The warning gets triggered for each template class Derived<int>; in your sources, so if you only see one warning, there will be only one vtable.
But there is a way to get rid of the warning: Do not have explicit instantiation, and rely on the compiler to instantiate the class implicitly.
For that you have to put all of your template definition in the header file. So move the definitions:
template<typename T>
bool Derived<T>::func(void) {return true;}
template<typename T>
Derived<T>::Derived(void) {}
into the header file, and remove extern template class Derived<int>; and
template class Derived<int>;

Why is my specialized template function invoked only in debug builds?

I have templated functions in my C++11 Xcode project and some of them have specializations. However, I have discovered that the specializations only get called in debug builds; if I build in release, they are ignored.
I have successfully created a very simple example:
special.h
#include <cstdio>
struct special
{
template<typename T>
void call(const T&) { puts("not so special"); }
};
special.cpp
#include "special.h"
#include <string>
template<>
void special::call(const std::string&) { puts("very special"); }
main.cpp
#include "special.h"
#include <string>
int main()
{
std::string str = "hello world";
special s;
s.call(123);
s.call(str);
}
You can download the project (until somewhere this summer of 2013 at least) to reproduce the issue if you don't want to create it yourself. First run the project with the debug configuration, then run it again in release. The output that I expect is:
not so special
very special
And this is indeed what I get with the Debug build configuration. However, with Release, I get this:
not so special
not so special
Which means the specialized implementation of special::call in special.cpp was ignored.
Why is the result inconsistent? What should I do to ensure that the specialized function is called in release builds?
Your program has UB. An explicit specialisation or at least its declaration must be visible before being used. [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.
Add this declaration to special.h:
template<>
void special::call(const std::string&);
Alternatively, you can put the specialistation itself into the header. However, as a specialisation is no longer a template, it follows normal function rules and must be marked inline if placed in a header.
Also, be careful that function template specialisations have rather specific behaviour, and it's generally better to use overloads than specialisations. See Herb Sutter's article for details.
You violated the one definition rule (ODR). So what happens exactly? In main.cpp there is no specialization known for special::call<string>. Therefore the compiler generates an instantiation of the template into that translation unit (TU) that outputs "not so special". In special.cpp there is a full specialization declared and defined, so the compiler puts that definition into the other translation unit. So you have two different definitions of the very same function in two different translation units, which is a violation of the ODR which means it is undefined behavior.
In theory, the outcome can be anything. A compiler error, a crash, a silent online order for a pizza, anything. Even different behavior in debug and release compiles.
In practice, I guess the following happens: When linking the debug build, the Linker sees the same symbol defined twice in the two TUs, which is allowed only for templates and inline functions. Because of the ODR it may assume that both definitions are equivalent and picks the one from special.cpp, so you get by coincidence the behavior you expect.
During release build, the compiler inlines the call to special::call<string> during the compilation of main.cpp, so you get the only behavior seen in that TU: "not so special".
So how can you fix this?
In order to have only one definition for that specialization, you have to define it in one TU as you did, but you have to declare that there is a full specialization in any other TU, meaning declare that the specialization exists in the header special.h:
// in special.h
template<>
void special::call(const std::string&);
Or, which is seen more often, define it in the header, so it's seen in every TU. Since fully specialized function templates are normal functions, you will have to define it inline:
// in special.h
template<>
inline void special::call(const std::string&)
{
puts("very special");
}

problem understanding templates in c++

Template code is not compiled until the template function is used. But where does it save the compiled code, is it saved in the object file from which used the template function in the first place?
For example,
main.cpp is calling a template function from the file test.h, the compiler generates an object file main.o,
Is the template function inside the main.o file? because template code is not inlined, is it?
It's totally compiler implementation dependant. Most compilers will generate code around, inline or in cpp-like files and then compile with that. Sometimes, with optimization setup, some compilers will even reuse the same code instead of recreate it for each cpp.
So you have to see your compiler's doc for more details.
Yes, the template function code is emitted in the main.o file. Some of it may be inlined, as any other code may be inlined, but in general, code for templates is emitted in any file in which the template is instantiated. Think of it as first instantiating the template code to produce normal non-template functions, and then compiling those functions with whatever inlining and optimization the compiler applies to any other function.
When the same template instantiation (e.g. std::vector<int>) occurs in multiple compilation units (.cpp files), there is a bit of difficulty, because the code is instantiated in each of them. There are various ways of handling this, sometimes involving a cleanup step in the linking phase where duplicate template instantiations are resolved into a single one; your compiler manual can provide more information on exactly how it handles that situation.
Template code is compiled even if it is never instantiated. Otherwise, compilers couldn't be required to emit a diagnostic for this:
template< typename T >
void f()
{
blah
}
Template compilation happens in two phases. Besides the basic checks, everything that depends on template parameters can only be checked when a template is instantiated and the formal parameters are filled in with actual types. For example, here
template< typename T >
void f()
{
typename T::nested_type x;
}
T::nested_type can only be checked after the template is instantiated and an actual type is given for T. However, a basic check ("given T::nested_type is a type, is this a valid variable definition?") is performed the moment the compiler encounters the template's definition. (That's why that typename is required, BTW. Depending on T, T::nested_type might just as well be the name of member of T or a static data member - which would make T::nested_type x; a syntax error. So we have to tell the compiler to treat T::nested_type as the name of a type.)
You mean instantiated, not compiled. At compile time the compiler finds out each and every version that your code uses and instatiates (in object files) all the required versions.
It is always inlined (meaning, it is always internal linkage, having inline semantics). It may in fact be not inlined after all, just as an inline function, however, template is not code. It is a "template for making code". Therefore, it will normally reside in a header, except special cases, see below.
There was an idea to make something else, codenamed "export keyword". It was removed from standard.
Special cases: you can compile template instantiations into an object file, without having them used. This is the only way to avoid having all template code inlined.
This is how it is done:
template class std::vector<MyClass>;
This will force the compiler to instantiate a template in the current location. C++0x will have a syntax to force compiler not to do it, and have the linker search for template instantiation elsewhere:
extern template class std::vector<MyClass>; // C++0x only

Templates and headers question

The compiler says it can't find the reference for the function when I do this:
// link.h
template <class T>
T *Link(T *&, T *(*)())
// link.cpp
template <class T>
T c:Link(T *&ChildNodeReference, T *(*ObjectCreator)()){
}
If I implement inside the class on the header it goes smoothly.
Please, I will work on the header until someone enlightens me about this.
There are somethings in C++ that are weirdly annoying. I know, there is a reason for this and etc. Even so, can't the compilers help you out about it -_-"
Templates are essentially semi-type-safe macros, hence the limitation.
Normal (non-template) functions can be compiled to native code residing object/library files, and then referenced with only a prototype available in the header, solely because there's only a single version of such a function.
With templates, C++ compiler has to compile each instantiation of the function separately. Obviously, it cannot do it "in advance", because the set of types for which you can instantiate the function is effectively unbounded (you can always define a new type in your code before calling the function). In fact, two instantiations of the same function template can be completely different. Consider this extreme case:
struct t1 {
template <int>
struct a {};
};
struct t2 {
enum { a = 123 };
};
enum { b = 456, c = 789 };
template <class T>
void foo() {
T::a<b>c;
}
Now if we call foo<t1>(), the statement inside it is a local variable declaration, because t1::a is a class template:
T::a<b> c;
But if we call foo<t2>(), the statement inside is an expression, because t2::a is an integral constant:
(T::a < b) > c;
This is just to show that compiler cannot meaningfully "compile" a template; it really has to mostly preserve the tokens.
Now, all that said, ISO C++ does actually provide the ability to separate declaration and definition of templates, so that they can be treated as normal functions, with declarations in .h files, and definitions in .cpp files. This is called "export templates", because you have to precede both declaration and definiton with keyword export:
// link.h
export template <class T>
T *Link(T *&, T *(*)());
// link.cpp
export template <class T>
T *Link(T *&ChildNodeReference, T *(*ObjectCreator)()) {
}
This is, however, a controversial feature of the Standard because of very high burden on implementation, and most popular implementations refuse to implement it; notably, g++, MSVC, and C++Builder do not implement it. The only compiler I know of that supports it is Comeau C++.
Programming non-template code or non-inlined functions in headers is a Bad Thing™. The reason you have cpp files is to prevent redefinition of the same function code more than once, amongst other things.
The difference with templates is that the compiler practically doesn't touch them until your code instantiates a specialisation of that template which is why they need to have their source inside the header.
When the compiler finds an instantiation of a template specialisation (say List<int>), it goes back to the included template code and compiles it with that specialisation, which is why you don't have issues with redefinition of function code.
What you don't seem to understand is that this doesn't apply to non-templated code. All non-template code is compiled as normal and thus CPP files are needed to only define the code once then link it all together.
If you define functions inside a header, your linker will not link the compiled translation units because they have defined the same function more than once.
Templated implementations (not only definitions) have to be available at compile time.
So, the full template code is normally put in the header file.
Template code must be in the header. Sorry, I completely missed that! (and I thought I'd been coding C++ for years :P)
You forgot the * for the return type. So implementation is not matching definition. Add it and it should work:
T *c:Link(T *&ChildNodeReference, T *(*ObjectCreator)())
{
}
Implementation must be too in the header file under the class definition in order to be available at compile time.

Visibility of template specialization of C++ function

Suppose I have fileA.h which declares a class classA with template function SomeFunc<T>(). This function is implemented directly in the header file (as is usual for template functions). Now I add a specialized implementation of SomeFunc() (like for SomeFunc<int>()) in fileA.C (ie. not in the header file).
If I now call SomeFunc<int>() from some other code (maybe also from another library), would it call the generic version, or the specialization?
I have this problem right now, where the class and function live in a library which is used by two applications. And one application correctly uses the specialization, while another app uses the generic form (which causes runtime problems later on). Why the difference? Could this be related to linker options etc? This is on Linux, with g++ 4.1.2.
It is an error to have a specialization for a template which is not visible at the point of call. Unfortunately, compilers are not required to diagnose this error, and can then do what they like with your code (in standardese it is "ill formed, no diagnostic required").
Technically, you need to define the specialization in the header file, but just about every compiler will handle this as you might expect: this is fixed in C++11 with the new "extern template" facility:
extern template<> SomeFunc<int>();
This explicitly declares that the particular specialization is defined elsewhere. Many compilers support this already, some with and some without the extern.
Have you added a prototype with parameters to your header file?
I mean is there somewhere in fileA.h
template<> SomeFunc<int>();
If not that's probably the reason.
I had the same problem with gcc4, here is how i solved it. It was more simple a solution than what i was lead to believe by previous comments. The previous posts ideas were correct but their syntax didn't work for me.
----------header-----------------
template < class A >
void foobar(A& object)
{
std::cout << object;
}
template <>
void foobar(int);
---------source------------------
#include "header.hpp"
template <>
void foobar(int x)
{
std::cout << "an int";
}
Per the specs, your specialized function template should never be called outside fileA.C, unless you export the template definition, which no compiler (except Comeau) currently supports (or has it planned for the forseeable future).
On the other hand, once the function template is instantiated, there is a function visible to the compiler that is no longer a template. GCC may re-use this definition across different compiler units because the standard states that each template shall only be instantiated once for a given set of type arguments [temp.spec]. Still, since the template is not exported, this should be limited to the compilation unit.
I believe that GCC may expose a bug here in sharing its list of instantiated templates across compilation units. Normally, this is a reasonable optimization but it should take function specializations into account which it doesn't seem to do correctly.
In Microsoft C++, I did an experiment with inline functions. I wanted to know what would happen if I defined incompatible versions of a function in different sources. I got different results depending on whether I was using a Debug build or a Release build. In Debug, the compiler refuses to inline anything, and the linker was linking the same version of the function no matter what was in scope in the source. In Release, the compiler inlined whichever version had been defined at the time, and you got differing versions of the function.
In neither case were there any warnings. I kind of suspected this, which is why I did the experiment.
I assume that template functions would behave the same, as would other compilers.
As Anthony Williams says, the extern template construct is the correct way to do this, but since his sample code is incomplete and has multiple syntax errors, here's a complete solution.
fileA.h:
namespace myNamespace {
class classA {
public:
template <class T> void SomeFunc() { ... }
};
// The following line declares the specialization SomeFunc<int>().
template <> void classA::SomeFunc<int>();
// The following line externalizes the instantiation of the previously
// declared specialization SomeFunc<int>(). If the preceding line is omitted,
// the following line PREVENTS the specialization of SomeFunc<int>();
// SomeFunc<int>() will not be usable unless it is manually instantiated
// separately). When the preceding line is included, all the compilers I
// tested this on, including gcc, behave exactly the same (throwing a link
// error if the specialization of SomeFunc<int>() is not instantiated
// separately), regardless of whether or not the following line is included;
// however, my understanding is that nothing in the standard requires that
// behavior if the following line is NOT included.
extern template void classA::SomeFunc<int>();
}
fileA.C:
#include "fileA.h"
template <> void myNamespace::classA::SomeFunc<int>() { ... }
Brandon: that's what I thought - the specialized function should never be called. Which is true for the second application I mentioned. The first app, however, clearly calls the specialized form even though the specialization is not declared in the header file!
I mainly seek enlightenment here :-) because the first app is a unit test, and it's unfortunate to have a bug that doesn't appear in the test but in the real app...
(PS: I have fixed this specific bug, indeed by declaring the specialization in the header; but what other similar bugs might still be hidden?)
#[anthony-williams],
are you sure you're not confusing extern template declarations with extern template instantiations? From what I see, extern template may only be used for explicit instantiation, not for specialization (which implies implicit instantiation). [temp.expl.spec] doesn't mention the extern keyword:
explicit-specialization:
template < > declaration
Unless the specialized template function is also listed in the header file, the other application will have no knowledge of the specialized version. The solution is the add SomeFunc<int>() to the header as well.