C++ templated function and forward declarations - c++

I'm working on some code that compiles and links (and even has released commercial products) on Windows using MSVC. It doesn't compile with GCC though, I get the following errors:
.../CBaseValue.h: In member function 'bool CBaseValue::InstanceOf()':
.../CBaseValue.h:90:18: error: invalid use of incomplete type 'struct CValueType'
.../CBaseValue.h:11:7: error: forward declaration of 'struct CValueType'
CBaseValue.h
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<_Type>();
}
}
...
}
CValueType.h
class CValueType : public CBaseValue {
public:
...
template <typename _Type>
bool IsDerivedFrom() {
return IsDerivedFrom(_Type::TYPEDATA);
}
...
}
I understand why this is a problem. The base class (CBaseValue) has a templated function that uses a derived class (in this case CValueType).
It looks like MSVC isn't exactly obeying the C++ spec here and I've just been bitten by it. But the MSVC behavior of using the forward declaration until code calling the templated function is actually compiled is also more desirable right now. Does anybody know of a work-around where I can get this code working with GCC without having to rewrite a lot of base code?
From my own research it looks like passing '-fno-implicit-templates' to g++ would help but then I'd need to explicitly define the called template types. There are a lot of them so if I can avoid that I'd prefer it. If the general consensus is that this is my best option... so be it!
And in case anybody is wondering, I'm porting the code over to the Mac which is why we're now using GCC.

This is ill-formed by the Standard, but no diagnostic is required. MSVC is fine not diagnosing this particular case (even when instantiation happens!).
More specifically, the (C++03) Standard rules at 14.6/7
If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required.
So the solution is to just make the type dependent, but arrange it that during instantiation, that type is designated. For example, you can do that by rewriting your template like this
template<typename T, typename> // just ignore second param!
struct make_dependent { typedef T type; };
template <typename Type> // eww, don't use "_Type" in user code
bool InstanceOf() {
typename make_dependent<CValueType, Type>::type* pType = GetType();
// ...
return pType->template IsDerivedFrom<Type>();
// ...
}

It seems that the CBaseValue::InstanceOf() function is useless to anyone not including CValueType.h.
So wait to provide the definition until all needed types are available. (EDIT: This is exactly what is suggested by Charles Bailey's comment that he posted while I was typing -- I guess we think alike.)
CBaseValue.h
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf();
...
}
CValueType.h
class CValueType : public CBaseValue {
public:
...
template <typename T>
bool IsDerivedFrom() {
return IsDerivedFrom(T::TYPEDATA);
}
...
}
template <typename T>
inline bool CBaseValue::InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<T>();
}
}
They seem very tightly coupled though, so maybe having just one header file for both classes, or one public header file that includes the individual headers in the correct order, would be better.

Related

Is this a bug in GCC?

EDIT: This is not a bug, just me not knowing about dependent name lookups in templated base classes (which MSVC "helpfully" resolves without errors).
I wrote a functor implementation a while back, and a simple "Event" wrapper that uses it. It compiles fine under MSVC, but GCC gives an error about a member variable in the base class, subscribers, not being declared; changing subscribers to this->subscribers resolves the issue(!). It appears to happen only with the curiously recurring template pattern, and with partial template specialization.
Simplified source (sorry for the mind-bending template usage...):
#include <vector>
template<typename TEvent>
struct EventBase
{
protected:
std::vector<int> subscribers;
};
template<typename TArg1 = void, typename TArg2 = void>
struct Event : public EventBase<Event<TArg1, TArg2> >
{
void trigger(TArg1 arg1, TArg2 arg2) const
{
// Error on next line
auto it = subscribers.cbegin();
}
};
template<typename TArg1>
struct Event<TArg1, void> : public EventBase<Event<TArg1> >
{
void trigger(TArg1 arg1) const
{
// Using `this` fixes error(?!)
auto it = this->subscribers.cbegin();
}
};
template<>
struct Event<void, void> : public EventBase<Event<> >
{
void trigger() const
{
// No error here even without `this`, for some reason!
auto it = subscribers.cbegin();
}
};
int main()
{
return 0;
}
Am I invoking undefined behaviour somewhere? Is my syntax somehow wrong? Is this really a bug in GCC? Is it perhaps a known bug? Any insight would be appreciated!
More details: Compiled using g++ -std=c++11 main.cpp. I'm using GCC version 4.7.2. Exact error message:
main.cpp: In member function ‘void Event<TArg1, TArg2>::trigger(TArg1, TArg2) const’:
main.cpp:17:15: error: ‘subscribers’ was not declared in this scope
This is a bug in MSVC instead. Names from dependent base classes have to be "thisambiguated".
The reason is that unqualified lookup of dependent names proceeds in two phases. During the first phase, the base class is not yet known and the compiler cannot resolve the name. MSVC does not implement two-phase name lookup and delays the lookup until the second phase.
The full specialization
template<>
struct Event<void, void> : public EventBase<Event<> >
{
void trigger() const
{
// No error here even without `this`, for some reason!
auto it = subscribers.cbegin();
}
};
does not suffer from this problem, because both the class and its base are regular classes, not class templates, and there is no template dependency to begin with.
When porting C++ code from MSVC to gcc/Clang, dependent name lookup disambiguation and the template keyword disambiguation (i.e. calling member function template using ::template, ->template or .template syntax) are two of the subtleties that you have to deal with (empty base optimization is another one). For all the Standards compliance rhetoric, this will probably never be fixed for reasons of backwards compatibility.

How to forward declare a C++ template class?

Given a template class like the following:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
How can someone forward declare this class in a header file?
This is how you would do it:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings;
template<typename Type, typename IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
Note that the default is in the forward declaration and not in the actual definition.
You can declare a templated class whose definition states the default arguments, but any time you reference the class you must include all its arguments until the definition is introduced.
eg. Let's use struct Foo without including it:
template <class>
struct Foo;
// Note that we *must* use the template here,
// even though in the definition it'll have a default.
template <class T>
auto Func (Foo<T> foo)
{
// do stuff with Foo before it's defined:
return foo.Bar();
}
int Func (int n)
{
return n;
}
We can then compile it without including the definition, eg.:
int main ()
{
return Func(3);
}
demo
...Or we can use it after including the definition, eg.:
template <class T = bool>
struct Foo
{
T Bar () {return 9;}
};
// Now the compiler understands how to handle
// Foo with no template arguments
// (making use of its default argument)
int main ()
{
return Func(Foo<>());
}
demo
I haven't checked the standards, but this works on clang/gcc with -std=c++98 up to -std=c++17, so if it's not officially a standard then it looks to be unofficially so.
Although in principal this should work for namespace std, and appears to in the examples I've checked (with many compilers), the standard states that it's undefined behaviour: According to the C++11 standard, 17.6.4.2.1:
The behavior of a C++ program is undefined if it adds declarations or
definitions to namespace std or to a namespace within namespace std
unless otherwise specified.
(I got this info from an SO answer).
Thanks to Antonio for pointing this out in the comments (and providing the link).
You can declare default arguments for a template only for the first declaration of the template. If you want allow users to forward declare a class template, you should provide a forwarding header. If you want to forward declare someone else's class template using defaults, you are out of luck!
My answer complements the others as the solution I found actually mitigates the need for a template class forward declaration by creating a new type when all parameters are known (or provided as default) so that this new type, than you can forward declare, is not a template anymore:
template<typename Type=MyDefault, typename IDType=typename Type::IDType>
class MappingsGeneric
{
...
};
class Mappings : public MappingsGeneric<> {};
You can then class Mappings;. I know that this solution doesn't apply everywhere but it did in my use case as I only used templates for high-performance dependency injection for non-virtual methods in a unit test context.

Is it valid C++ to implement a template class's methods differently for different types without using specialization syntax?

I'm code reviewing a colleagues code and found this:
Header file:
template<class T>
class MyClass
{
void Execute();
}
Cpp file:
void MyClass<int>::Execute()
{
// something
}
void MyClass<string>::Execute()
{
// something else
}
The code is specializing the function, but without using template specialization syntax. I guess it's working ok, but is it valid?
Yes, it's perfectly valid to specialize methods of a template class.
But your syntax is wrong, it should be: (sorry, didn't see you were missing the template<> initially. Just assumed it was there and thought you were asking about member function specialization.)
template<>
void MyClass<int>::Execute()
{
// something
}
template<>
void MyClass<string>::Execute()
{
// something else
}
You need only declare these in the header. If you implement them in the header as well, you'll need to mark them inline to prevent multiple definition.
When calling a method, the version that suits the call most is called. Otherwise, the default.
In your case, if you specialize the template with a class X and attempt to call Execute, you'll get a linker error because you haven't provided a default implementation, nor a specialization for Execute for X.
The question has already been answered, but let me draw attention to subtle differences between three cases.
Case 1: Specialization
header:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
template <> void Foo<int>::f();
source:
template <> void Foo<int>::f() { /* ... */ }
In this case, Foo<T>::f() can be called for any T. The definition for the general case is auto-generated from the template; the definition for Foo<int>::f() is the one provided. Having the specialization in the header alerts every consuming translation unit that a separate symbol is to be looked up, rather than to use the template.
Case 2: Definition
header:
template <typename T> struct Foo
{
void f();
};
source:
template <> void Foo<int>::f() { /* ... */ }
In this case, only Foo<int>::f() can be used; everything else will cause a linker error. Since there is no definition of the function in the template, every use of the template will cause a new symbol to be emitted, and only the one for Foo<int>::f() is provided by the shown translation unit.
Case 3: Flagrant error
header:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
source:
template <> void Foo<int>::f() { /* ... */ }
This is a violation of the one-definition rule, since there are now multiple definitions of Foo<int>::f().
This is the old syntax for explicit specialization. But I'm surprised that you are using a compiler which still accept it (g++ stopped around 4.0). To be conforming you need to prefix the specialization with template <>.
To answer the question in the title as originally written: absolutely. It's also valid to have a completely unrelated set of members in a specialization.
To answer the question in the code: looks to me like a compiler bug. The template <> is required.

C++ Templates challenge

I've been facing a big challenge (for me, at least) regarding templates instancing and inheritance. Let's see this code:
class Convertible
{
public:
template<class T>
T* AsPtrTo()
{
return reinterpret_cast<T*>(this);
}
};
template<class T>
class TemplateBase : public Convertible
{
};
template<class T>
class TemplateDerived : public TemplateBase<T>
{
public:
void Method1(TemplateBase<T> t)
{
t.AsPtrTo<int>(); // <<<<<< ERROR
}
};
int main()
{
TemplateDerived<int> d;
TemplateBase<int> b;
d.Method1(b);
return 0;
}
As you can see, there is a class, called Convertible, with only one template method that performs a type casting. There is also a template class that inherits from Convertible, and then another template class that inherits from the previous one. This last template class implements a method that uses the template method AsPtrTo which should be inherited from Convertible and instanced during compilation for the type T, used in the main function.
For some reason I can't understand, this fails. GCC 4.4.1 gives me this message:
error: expected primary-expression before 'int'
I've marked the line of the error.
I thought maybe one of the C++ experts here could lend me a hand.
Thanks everybody in advance!
You need to use the keyword template as:
t.template AsPtrTo<int>();
This has been discussed so many times that you will find innumerable number of posts on SO.
But here you will find one of the best explanation:
Where and why do I have to put the "template" and "typename" keywords?
Try:
void Method1(TemplateBase<T> t)
{
t.template AsPtrTo<int>();
}
The reason is that the compiler doesn't know what member functions t has at parse time, so it doesn't know if AsPtrTo is a template function or not. Because of this, it can't parse it properly without the hint.
As an example for why this is needed, consider the following code:
struct Foo
{
template<int N> int foo(int x) { return x + N; }
};
struct Bar
{
int foo;
};
template <typename T>
int baz(T t)
{
return t.foo<0>(1);
}
At a glance, it looks like baz<Foo> would work, but baz<Bar> wouldn't, but it's the other way round!
Consider what happens if I call baz<Bar>
return t.foo<0>(1);
foo is a member variable, so when it sees the < it thinks it's a less-than operator, so it parses the expression like this:
return (t.foo < 0) > (1);
Which is a valid expression (after some implicit conversions to/from bool)!
The thing is, it parses the expression like that for both Foo and Bar, which is why the template keyword is needed. Compilers have to assume that it is not a template member function (unless you put that keyword there).

g++ template bug or VC too liberal?

I am writing a heavily templated piece of code in C++. It worked perfectly in VS 2005 but when I try to compile it in g++ I get some really strange errors.
The essential piece of code (simplified to a minimum, doesn't compile either) is as follows:
template <class Actual>
class Generic
{
public:
typedef Actual ThisType;
};
template <class Actual>
class Intermediate : public Generic<Actual>
{
};
template <class Q>
class Derived : public Intermediate<Derived<Q> >
{
public:
void FooBar()
{
ThisType q;
}
};
The error is:
"'ThisType' was not declared in this scope"
in the line where 'q' is being declared.
Curiously, everything works fine when Derived is not a template but a plain class. Why would compiler look into template function implementation before it is even instantiated? I know that VC++ checks far too little when compiling templates (unused templates can even contain syntactically incorrect code) - but isn't g++ checking too much here? I tried adding a typename keyword with little hope and it fails too. Is there any way to get ThisType to work as expected? I dread the thought of adding it manually to every single derived class - it's cumbersome, redundant, inelegant and error-inducing.
Best regards,
MZ
Unqualified names are not looked up in dependent base classes (your base class depends on template parameter Q). Qualify that name, and it will work.
typename Derived::ThisType q;
Trust in Comeau online compiler!
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions
"ComeauTest.c", line 19: error: identifier "ThisType" is undefined
ThisType q;
^
"ComeauTest.c", line 19: error: expected a ";" (perhaps on the previous statement)
ThisType q;
^
2 errors detected in the compilation of "ComeauTest.c".
Dependent type names from inherited classes are not taken into account, you might try to explicitly request ThisType:
typename Intermediate<Derived<Q> >::ThisType q;
The code is indeed ill-formed. When base class depends on template parameter it is not considered by name lookup when looking for unqualified names.
In your case unqualified name ThisType will not be looked up in base class Intermediate<Derived<Q> > because your base class depends on template parameter Q.
You are missing a typename
template <class Actual> class Generic { public:
typedef Actual ThisType; };
template <class Actual> class Intermediate : public Generic<Actual> { };
template <class Q> class Derived : public Intermediate<Derived<Q> > { public:
void FooBar()
{
typename Derived::ThisType q;
return *this;
} };
int main(){}