C++ template class behaves differently for different compilers - c++

I am working with templates in C++. Is there any difference in using templates and friend class when compiled with MSVC compiler and when using Mingw gcc compiler. My code successfully compiles and gives the desired output when compiled with MSVC but it gives error when compiled with gcc. Below is my code,
///////////Record.h/////////////////////
#include "Base.h"
class Derived1;
class Derived2;
template <class TYPE_LIST> class List;
class FRecord
{
public:
FRecord();
virtual ~FRecord();
friend class Base;
#if _MSC_VER <= 1200
friend class List<Derived1>;
friend class List<Derived2>;
#else
template <class TYPE_LIST> friend class List;
#endif
};
///////////////////////////////////////////////////////////////
///////////////////Base.h/////////////////////////////////
class Base
{
public:
Base(const HEADER *hc, const FRecord *fr);
virtual ~Base();
__inline bool IsNonValid() const;
protected:
quint32 Size;
};
/////////////////////////////////////
// Data
/////////////////////////////////////
template <class TYPE_LIST>
class Data : public TYPE_LIST
{
public:
Data(const HEADER *hc, const FRecord *fr) : TYPE_LIST(hc, fr)
{
QString val = IsNonValid() ? "Non" : "";
LOG0("Data ("<< val << " Valid)");
}
virtual ~Data()
{
LOG0("Data deleted");
}
}; // Data
///////////////////////////////////////////////////////////////////////////////////////
When compiled the above code with MSVC gives desired output but when compiled with Mingw GCC compiler it gives following error,
Base.h:1154: error: there are no arguments to 'IsNonValid' that depend on a template parameter, so a declaration of 'IsNonValid' must be available
Base.h:1553: error: 'Size' was not declared in this scope
What could be the possible solution to this problem?
Thanks in advance.

MSVC does not implement two-phase name lookup correctly. GCC is correct in reporting this error.
The cause is that names used inside a template which do not depend on the template's parameters are (should be in the case of VC) looked up when the template is defined, not when it's instantiated.
In your case, the compiler has no way of telling that IsNonValid will come from the base class, so it rightfully complains it doesn't know it. There are two possible solutions:
Qualify the access to IsNonValid, so that it's clear to the compiler it (potentially) depends on the template parameters:
QString val = this->IsNonValid() ? "Non" : "";
// or
QString val = TYPE_LIST::IsNonValid() ? "Non" : "";
Introduce the inherited name into the scope of the derived class:
template <class TYPE_LIST>
class Data : public TYPE_LIST
{
public:
using TYPE_LIST::IsNonValid;
// the rest as you had it originally
Either of these will make the name dependent and thus postpone its lookup until instnatiation, when the value of TYPE_LIST is actually known.

gcc is correct. You need to add this-> to delay lookup until instantiation time.
this->IsNonValid();
MSVC is non-conforming in that it delays all lookups until instantiation time as it doesn't properly implement two-phase name lookup.

Related

How does template class instantiation work together with class inheritance?

Code
I have the following snippets of 2 classes with a separate source and header file. The derived class is a template class.
handler.h
class BaseHandler {
public:
BaseHandler(){}
BaseHandler(const std::string& directive);
virtual ~BaseHandler();
virtual bool operator()();
private:
const std::string m_directive;
};
template<typename C>
class DirectiveHandler : public BaseHandler {
public:
DirectiveHandler(const std::string& directive);
~DirectiveHandler();
bool operator()() override;
private:
std::vector<C> m_configurations;
};
handler.cpp
#include "handler.h"
BaseHandler::BaseHandler(const std::string& directive) : m_directive(directive) {};
BaseHandler::~BaseHandler(){};
template<typename C>
DirectiveHandler<C>::DirectiveHandler(const std::string& directive) :
BaseHandler(directive) {};
template<typename C>
bool DirectiveHandler<C>::operator()(){ return true; };
main.cpp
#include "handler.h"
template class DirectiveHandler<double>; //explicit template instantiation
int main(int argc, char *argv[]){
....
To my understanding I need to instantiate the template after it has been defined, this can happen either implicitly (leave out template class DirectiveHandler<double>;) or explicitly.
I'm assuming that implicit instantiation fails due to the separation of definition and declaration in the respective source and header file.
With the snippet of main.cpp above I have the following warnings:
warning: explicit template instantiation DirectiveHandler<double> will emit a vtable in every translation unit
warning: instantiation of function DirectiveHandler<double>::operator() required here, but no definition available
If change template class DirectiveHandler<double> to extern template class DirectiveHandler<double>;both warnings dissapear. I do understand why warning 2 is cleared, because the template class resides in handler.cpp. I fail to see how it clears warning 1 as well.
Question
Why does the addition of the extern keyword clear warning 1 (see above)?
I assume, you are compiling your code with CLang? (To the best of my knowledge, it is CLang warning, unless g++ started to emit it as well).
On any rate, the answer to the question as asked (I only have to assume that OP understands everything else) is the simple fact that template class DirectiveHandler<double>; - which is implicit template instantiation definition, which produces vtbls and such. (The fact that the warning is emitted for .cpp file might be actually a bug, but OP doesn't ask about it).
On the other hand, extern template class DirectiveHandler<double>; is not a definition. It is a declaration, which doesn't on itself trigger vptr's generation - and thus you see no warning.

Template undefined reference on windows with MinGW 4.8

I am using static template members in a class; the templates are instantiated in a cpp built in a software. I have a plug-in for the software that uses the name() template method in the header, but does not build the source file which contains the instantiation. The build works on Linux with g++-4.9 but fails on MinGW 4.8. I want to know how to make it work with the almost same compiler, but on Windows instead.
.hpp :
enum class ToplevelMenuElement
{
FileMenu,
...
AboutMenu
};
enum class FileMenuElement
{
New,
... ,
Quit
};
// Others menus macros are defined
class MenuInterface
{
public:
template<typename MenuType>
static QString name(MenuType elt);
private:
static const std::map<ToplevelMenuElement, QString> m_map;
static const std::map<FileMenuElement, QString> m_fileMap;
};
.cpp :
template<>
QString MenuInterface::name(ToplevelMenuElement elt)
{
return m_map.at(elt);
}
template<>
QString MenuInterface::name(FileMenuElement elt)
{
return m_fileMap.at(elt);
}
const std::map<ToplevelMenuElement, QString> MenuInterface::m_map
{
{ToplevelMenuElement::FileMenu, QObject::tr("File")},
...
{ToplevelMenuElement::AboutMenu, QObject::tr("About")}
};
const std::map<FileMenuElement, QString> MenuInterface::m_fileMap
{
{FileMenuElement::New, QObject::tr("New")},
...,
{FileMenuElement::Quit, QObject::tr("Quit")}
};
Error :
undefined reference to `QString MenuInterface::name<ToplevelMenuElement>(ToplevelMenuElement)'
Is there any flag to use to make some kind of lazy instantiation ? Or should I build the .cpp containing the template instantiation in my plug-in ?
Because you are linking a source file that contains explicit specializations, you need to declare your explicit specializations before you define them. From §14.7.3/3:
A declaration of a function template, class template, or variable template being explicitly specialized shall precede the declaration of the explicit specialization. [ Note: A declaration, but not a definition of the template is required. — end note ]
So you need to put these after your class in your header file:
template<>
QString MenuInterface::name(ToplevelMenuElement elt);
template<>
QString MenuInterface::name(FileMenuElement elt);
This has been asked many times...declaration and definitions for templates should be same file.

explicit template instantiation: MSVC vs. GCC

I'm trying to deal with namespaces & templates in C++. I can get the following code to compile in MSVC (no warnings or errors), but am having no luck at all with various permutations with CYGWIN/GCC. Any help would be appreciated.
In the header file I declare a templated subclass as follows:
#include <gdal.h>
namespace sfms {
template <class _type, GDALDataType _gdal> class SmfsGrid_Typed : public SfmsGrid_Base {
public:
SmfsGrid_Typed();
SmfsGrid_Typed(const SmfsGrid_Typed<_type, _gdal> *toCopy);
SmfsGrid_Typed(std::string filename);
virtual ~SmfsGrid_Typed();
virtual bool OpenRead();
virtual bool OpenWrite();
protected:
_type m_nodata_value;
virtual SfmsGrid_Base *New() const;
virtual SfmsGrid_Base *New(SfmsGrid_Base *toCopy) const;
virtual void initCopy(SfmsGrid_Base *copy) const;
};
template SmfsGrid_Typed<double, GDT_Float64>;
template SmfsGrid_Typed<float, GDT_Float32>;
template SmfsGrid_Typed<int, GDT_Int32>;
typedef SmfsGrid_Typed<double, GDT_Float64> SmfsGrid_Double;
typedef SmfsGrid_Typed<float, GDT_Float32> SmfsGrid_Float;
typedef SmfsGrid_Typed<int, GDT_Int32> SmfsGrid_Int;
}
In the source file I instantiate the specialized template class as follows:
void hi_there() {
//...
sfms::SmfsGrid_Typed<int, GDT_Int32> *grid = new sfms::SmfsGrid_Typed<int, GDT_Int32>(filey);
//...
sfms::SmfsGrid_Int *grid2 = new sfms::SmfsGrid_Int(filey);
//...
}
GDALDataType is an enum, but that doesn't seem to the the issue.
I've tried the class declaration inside and outside the namespace, with no success.
The source file containing the implementations for the templates compile okay with both compilers.
I've tried dropping the explicit template instantation and including the relevant C++ source file, also with no joy.
I've tried 'template', 'typename' and 'typedef' keywords in various different places (in the templated class def'n and where I try to create the object) with no success, but various interesting and often misleading error messages with GCC, such as:
error: 'SmfsGrid_Typed' is not a member of 'sfms'
when it clearly is! :) Regardless, any help on porting this code from MSVC to GCC would help.
Thanks!
Your explicit template instantiation looks wrong. Try replacing it with
template class SmfsGrid_Typed<double, GDT_Float64>;
template class SmfsGrid_Typed<float, GDT_Float32>;
template class SmfsGrid_Typed<int, GDT_Int32>;
(Note the added class keyword)

Inlining causes specialized member function of template class overriding virtual functions to get overlooked

I wanted to share a strange example with you guys that I stumbled upon and that kept me thinking for two days.
For this example to work you need:
triangle-shaped virtual inheritance (on member function getAsString())
member function specialization of a template class (here, Value<bool>::getAsString()) overriding the virtual function
(automatic) inlining by the compiler
You start with a template class that virtually inherits a common interface - i.e. a set of virtual functions. Later, we will specialize one of these virtual functions. Inlining may then cause our specilization to get overloooked.
// test1.cpp and test2.cpp
#include <string>
class ValueInterface_common
{
public:
virtual ~ValueInterface_common() {}
virtual const std::string getAsString() const=0;
};
template <class T>
class Value :
virtual public ValueInterface_common
{
public:
virtual ~Value() {}
const std::string getAsString() const;
};
template <class T>
inline const std::string Value<T>::getAsString() const
{
return std::string("other type");
}
Next, we have to inherit this Value class and the interface in a Parameter class that itself needs to be templated as well:
// test1.cpp
template <class T>
class Parameter :
virtual public Value<T>,
virtual public ValueInterface_common
{
public:
virtual ~Parameter() {}
const std::string getAsString() const;
};
template<typename T>
inline const std::string Parameter<T>::getAsString() const
{
return Value<T>::getAsString();
}
Now, do not(!) give the forward declaration of a specialization for Value for type equaling bool ...
// NOT in: test1.cpp
template <>
const std::string Value<bool>::getAsString() const;
But instead simply give its definition like this ...
// test2.cpp
template <>
const std::string Value<bool>::getAsString() const
{
return std::string("bool");
}
.. but in another module (that's important)!
And finally, we have a main() function to test what is happening:
// test1.cpp
#include <iostream>
int main(int argc, char **argv)
{
ValueInterface_common *paraminterface = new Parameter<bool>();
Parameter<int> paramint;
Value<int> valint;
Value<bool> valbool;
Parameter<bool> parambool;
std::cout << "paramint is " << paramint.getAsString() << std::endl;
std::cout << "parambool is " << parambool.getAsString() << std::endl;
std::cout << "valint is " << valint.getAsString() << std::endl;
std::cout << "valbool is " << valbool.getAsString() << std::endl;
std::cout << "parambool as PI is " << paraminterface->getAsString() << std::endl;
delete paraminterface;
return 0;
}
If you compile the code as follows (I placed it into two modules named test1.cpp and test2.cpp where the latter only contains the specialization and necessary declarations):
g++ -O3 -g test1.cpp test2.cpp -o test && ./test
The output is
paramint is other type
parambool is other type
valint is other type
valbool is bool
parambool as PI is other type
If you compile with -O0 or just -fno-inline - or also if you do give the forward declaration of the specialization - the result becomes:
paramint is other type
parambool is bool
valint is other type
valbool is bool
parambool as PI is bool
Funny, isn't it?
My explanation so far is: Inlining is at work in the first module (test.cpp). The required template functions get instantiated but some just end up being inlined in the calls to Parameter<bool>::getAsString(). On the other hand, for valbool this did not work but the template is instantiated and used as a function. The linker then finds both the instantiated template function and the specialized one given in the second module and decides for the latter.
What do you think of it?
do you consider this behavior a bug?
Why does inlining work for Parameter<bool>::getAsString() but not for Value<bool>::getAsString() although both override a virtual function?
I speculate that you have an ODR problem, so there is little sense in guessing why some compiler optimization behaves differently from another compiler setting.
In essence, the One Definition Rule states that the same entity should
have the exact same definition throughout an application, otherwise the
effects are undefined.
The fundamental problem is that the code that doesn't see the specialized version of your class template member function might still compile, is likely to link, and sometimes might even run. This is because in the absence of (a forward declaration of) the explicit specialization, the non-specialized version kicks in, likely implementing a generic functionality that works for your specialized type as well.
So if you are lucky, you get a compiler error about missing declarations/definitions, but if you are really unlucky you get "working" code that does not what you intend it to do.
The fix: always include (forward) declarations of all template specializations. It's best to put those in a single header and include that header from all clients that call your class for any possible template argument.
// my_template.hpp
#include "my_template_fwd.hpp"
#include "my_template_primary.hpp"
#include "my_template_spec_some_type.hpp"
// my_template_fwd.hpp
template<typename> class my_template; // forward declaration of the primary template
// my_template_primary.hpp
#include "my_template_fwd.hpp"
template<typename T> class my_template { /* full definition */ };
// my_template_spec_some_type.hpp
#include "my_template_fwd.hpp"
template<> class my_template<some_type> { /* full definition */ };
// some_client_module.hpp
#include "my_template.hpp" // no ODR possible, compiler will always see unique definition
Obviously, you could reorganize the naming by making subdirectories for template specializations and change the include paths accordingly.

Is it possible trigger a compiler / linker error if a template has not been instantiated with a certain type?

Follow-up question to [Does casting to a pointer to a template instantiate that template?].
The question is just as the title says, with the rest of the question being constraints and usage examples of the class template, aswell as my tries to achieve the goal.
An important constraint: The user instantiates the template by subclassing my class template (and not through explicitly instantiating it like in my tries below). As such, it is important to me that, if possible, the user doesn't need to do any extra work. Just subclassing and it should work (the subclass actually registers itself in a dictionary already without the user doing anything other than subclassing an additional class template with CRTP and the subclass is never directly used by the user who created it). I am willing to accept answers where the user needs to do extra work however (like deriving from an additional base), if there really is no other way.
A code snippet to explain how the class template is going to be used:
// the class template in question
template<class Resource>
struct loader
{
typedef Resource res_type;
virtual res_type load(std::string const& path) const = 0;
virtual void unload(res_type const& res) const = 0;
};
template<class Resource, class Derived>
struct implement_loader
: loader<Resource>
, auto_register_in_dict<Derived>
{
};
template<class Resource>
Resource load(std::string const& path){
// error should be triggered here
check_loader_instantiated_with<Resource>();
// search through resource cache
// ...
// if not yet loaded, load from disk
// loader_dict is a mapping from strings (the file extension) to loader pointers
auto loader_dict = get_all_loaders_for<Resource>();
auto loader_it = loader_dict.find(get_extension(path))
if(loader_it != loader_dict.end())
return (*loader_it)->load(path);
// if not found, throw some exception saying that
// no loader for that specific file extension was found
}
// the above code comes from my library, the code below is from the user
struct some_loader
: the_lib::implement_loader<my_fancy_struct, some_loader>
{
// to be called during registration of the loader
static std::string extension(){ return "mfs"; }
// override the functions and load the resource
};
And now in tabular form:
User calls the_lib::load<my_fancy_struct> with a resource path
Inside the_lib::load<my_fancy_struct>, if the resource identified by the path isn't cached already, I load it from disk
The specific loader to be used in this case is created at startup time and saved in a dictionary
There is a dictionary for every resource type, and they map [file extension -> loader pointer]
If the dictionary is empty, the user either
didn't create a loader for that specific extension or
didn't create a loader for that specific resource
I only want the first case to have me throw a runtime exception
The second case should be detected at compile / link time, since it involves templates
Rationale: I'm heavily in favor of early errors and if possible I want to detect as many errors as possible before runtime, i.e. at compile and link time. Since checking if a loader for that resource exists would only involve templates, I hope it's possible to do this.
The goal in my tries: Trigger a linker error on the call to check_error<char>.
// invoke with -std=c++0x on Clang and GCC, MSVC10+ already does this implicitly
#include <type_traits>
// the second parameter is for overload resolution in the first test
// literal '0' converts to as well to 'void*' as to 'foo<T>*'
// but it converts better to 'int' than to 'long'
template<class T>
void check_error(void*, long = 0);
template<class T>
struct foo{
template<class U>
friend typename std::enable_if<
std::is_same<T,U>::value
>::type check_error(foo<T>*, int = 0){}
};
template struct foo<int>;
void test();
int main(){ test(); }
Given the above code, the following test definition does achieve the goal for MSVC, GCC 4.4.5 and GCC 4.5.1:
void test(){
check_error<int>(0, 0); // no linker error
check_error<char>(0, 0); // linker error for this call
}
However, it should not do that, as passing a null pointer does not trigger ADL. Why is ADL needed? Because the standard says so:
§7.3.1.2 [namespace.memdef] p3
[...] If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). [...]
Triggering ADL through a cast, as in the following definition of test, achieves the goal on Clang 3.1 and GCC 4.4.5, but GCC 4.5.1 already links fine, as does MSVC10:
void test(){
check_error<int>((foo<int>*)0);
check_error<char>((foo<char>*)0);
}
Sadly, GCC 4.5.1 and MSVC10 have the correct behaviour here, as discussed in the linked question and specifically this answer.
The compiler instatiates a template function whenever it is referenced and a full specification of the template is available. If none is available, the compiler doesn't and hopes that some other translation unit will instantiate it. The same is true for, say, the default constructor of your base class.
File header.h:
template<class T>
class Base
{
public:
Base();
};
#ifndef OMIT_CONSTR
template<class T>
Base<T>::Base() { }
#endif
File client.cc:
#include "header.h"
class MyClass : public Base<int>
{
};
int main()
{
MyClass a;
Base<double> b;
}
File check.cc:
#define OMIT_CONSTR
#include "header.h"
void checks()
{
Base<int> a;
Base<float> b;
}
Then:
$ g++ client.cc check.cc
/tmp/cc4X95rY.o: In function `checks()':
check.cc:(.text+0x1c): undefined reference to `Base<float>::Base()'
collect2: ld returned 1 exit status
EDIT:
(trying to apply this to the concrete example)
I'll call this file "loader.h":
template<class Resource>
struct loader{
typedef Resource res_type;
virtual res_type load(std::string const& path) const = 0;
virtual void unload(res_type const& res) const = 0;
loader();
};
template<class Resource>
class check_loader_instantiated_with : public loader<Resource> {
virtual Resource load(std::string const& path) const { throw 42; }
virtual void unload(Resource const& res) const { }
};
template<class Resource>
Resource load(std::string const& path){
// error should be triggered here
check_loader_instantiated_with<Resource> checker;
// ...
}
And another file, "loader_impl.h":
#include "loader.h"
template<class Resource>
loader<Resource>::loader() { }
This solution has one weak point that I know of. Each compilation unit has a choice of including either only loader.h or loader_impl.h. You can only define loaders in compilation units that include loader_impl, and in those compilation units, the error checking is disabled for all loaders.
After thinking a bit about your problem, I don't see any way to achieve this. You need a way to make the instantiation "export" something outside the template so that it can be accessed without referencing the instantiation. A friend function with ADL was a good idea, but unfortunately it was shown that for ADL to work, the template had to be instantiated. I tried to find another way to "export" something from the template, but failed to find one.
The usual solution to your problem is to have the user specializes a trait class:
template < typename Resource >
struct has_loader : boost::mpl::false_ {};
template <>
struct has_loader< my_fancy_struct > : boost::mpl::true_ {};
To hide this from the user, you could provide a macro:
#define LOADER( loaderName, resource ) \
template <> struct has_loader< resource > : boost::mpl::true_ {}; \
class loaderName \
: the_lib::loader< resource > \
, the_lib::auto_register_in_dict< loaderName >
LOADER( some_loader, my_fancy_struct )
{
public:
my_fancy_struct load( std::string const & path );
};
It is up to you to determine whether having this macro is acceptable or not.
template <class T>
class Wrapper {};
void CheckError(Wrapper<int> w);
template <class T>
class GenericCheckError
{
public:
GenericCheckError()
{
Wrapper<T> w;
CheckError(w);
}
};
int main()
{
GenericCheckError<int> g1; // this compiles fine
GenericCheckError<char> g2; // this causes a compiler error because Wrapper<char> != Wrapper<int>
return 0;
}
Edit:
Alright this is as close as I can get. If they subclass and either instantiate OR define a constructor that calls the parent's constructor, they will get a compiler error with the wrong type. Or if the child class is templatized and they subclass and instantiate with the wrong type, they will get a compiler error.
template <class T> class Wrapper {};
void CheckError(Wrapper<int> w) {}
template <class T>
class LimitedTemplateClass
{
public:
LimitedTemplateClass()
{
Wrapper<T> w;
CheckError(w);
}
};
// this causes no compiler error
class UserClass : LimitedTemplateClass<int>
{
UserClass() : LimitedTemplateClass<int>() {}
};
// this alone (no instantiation) causes a compiler error
class UserClass2 : LimitedTemplateClass<char>
{
UserClass2() : LimitedTemplateClass<char>() {}
};
// this causes no compiler error (until instantiation with wrong type)
template <class T>
class UserClass3 : LimitedTemplateClass<T>
{
};
int main()
{
UserClass u1; // this is fine
UserClass2 u2; // this obviously won't work because this one errors after subclass declaration
UserClass3<int> u3; // this is fine as it has the right type
UserClass3<char> u4; // this one throws a compiler error
return 0;
}
Obviously you can add other accepted types by defining additional CheckError functions with those types.