I'm wondering if the following code should be considered valid c++, gcc and clang both choke on it while Microsoft and the embedded compiler (green hills) our project uses seem to parse this without problems. This line of code gives gcc and clang trouble:
foo().Bar<int>();
It appears gcc thinks the < is a less than operator instead of specifying a template argument. If Bar is changed to not be a template function gcc accepts it.
class Test1
{
public:
template<typename U>
static void Bar() {}
};
template<typename T>
class Test2
{
public:
Test2()
{
foo().Bar<int>();
}
Test1 foo() { return t; }
Test1 t;
};
int main()
{
Test2<int> t;
}
From my research calling a static member function on an object instance is valid c++. So what are you thoughts? Here is gcc's error:
Error.cpp: In constructor ‘Test2<T>::Test2()’:
Error.cpp:14:17: error: expected primary-expression before ‘int’
foo().Bar<int>();
^
Error.cpp:14:17: error: expected ‘;’ before ‘int’
The correct syntax is:
foo().template Bar<int>();
(Adding to #Dieter answer)
Otherwise you have to use a temporary:
Test1 tt = foo();
tt.Bar<int>();
(in this case you could have simply used t instead of tt, but that was not the point, of course).
I asked this question already on http://www.cplusplus.com/forum/general/96128/ but to no avail.
does anybody experienced the same bug with g++ 4.2: internal compiler error: in make_thunk, at cp/method.c:129
I think it is not neccessary to include sample code. The respective code compiles without warnings and errors on several other newer g++ versions, as well as on clang++. It is simply correct and the bug was mentioned in the GCC's bugzilla (even several times, because it seems to recurr often), but no workaround was provided.
Please don't tell also to use a newer g++. I MUST compile it on the g++ shipped with Ubuntu Hardy, so I cannot change the compiler. Main development is done on Ubuntu Precise, but I need to keep it compatible to Hardy.
I have no idea what a thunk should be, I only suspect it has to do with covariants and/or multiple inheritance. Also I have several more similar structured header files, which all compile well, despite the only change is the name is the name of the class and I have no aim, to change that because of a compiler bug on Hardy.
Another fact is, it happens at include time.
In file included from /home/heiko/hgl/src/compiler/compilerprojectfactory.cpp:18:
/home/heiko/hgl/src/compiler/compilertype.h: In instantiation of 'HGL::Compiler::CompilerType<HGL::Vector2D, HGL::Compiler::CompilerBase>':
/home/heiko/hgl/src/compiler/compilervector2d.h:23: instantiated from here
/home/heiko/hgl/src/compiler/compilertype.h:22: internal compiler error: in make_thunk, at cp/method.c:129
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.
For Debian GNU/Linux specific bug reporting instructions,
see <URL:file:///usr/share/doc/gcc-4.2/README.Bug
EDIT: Here the header which causes the bug:
#include "compilertype.h"
#include "vector2d.h"
namespace HGL {
class Vector2D;
namespace Compiler {
/**
#author Heiko Schäfer <heiko#rangun.de>
*/
class _LOCAL Vector2D : public Compiler::CompilerType<HGL::Vector2D> {
DISALLOW_COPY_AND_ASSIGN(Vector2D)
public:
Vector2D(float x, float y, int line);
using IType::operator=;
virtual operator HGL::Vector2D &() const throw(InvalidExpressionException);
protected:
virtual ~Vector2D();
void append(ISerializeable::BUFFER *dest, const HGL::IType *type) const;
};
}
}
Here the template:
#include "compilerbase.h"
#include "iproject.h"
#include "util.h"
namespace HGL {
namespace Compiler {
const IProject::VSTRUCT minReq = { HGL_MINREQ_MAJOR, HGL_MINREQ_MAJOR, HGL_MINREQ_MAJOR };
template<class Type, class Base = CompilerBase>
class _LOCAL CompilerType : public Type, public Base {
DISALLOW_COPY_AND_ASSIGN(CompilerType)
public:
using IType::operator=;
template<class Param>
inline CompilerType(const Param &p, bool b, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) :
Type(p), Base(line, b) {
init(vs);
}
template<class Param>
inline CompilerType(const Param &p, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) : Type(p), Base(line) {
init(vs);
}
inline CompilerType(bool b, int line, const IProject::VSTRUCT &vs = IProject::VSTRUCT())
: Type(), Base(line, b) {
init(vs);
}
template<class Param1, class Param2>
inline CompilerType(const Param1 &p1, const Param2 &p2, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) :
Type(p1, p2), Base(line) {
init(vs);
}
template<class Param1, class Param2>
inline CompilerType(const Param1 &p1, const Param2 &p2, bool b, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) : Type(p1, p2),
Base(line, b) {
init(vs);
}
inline CompilerType(int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) : Type(), Base(line) {
init(vs);
}
inline virtual void append(ISerializeable::BUFFER *dest, const IType *type) const {
Base::append(dest, type);
}
protected:
inline virtual ~CompilerType() {}
inline virtual void init(const IProject::VSTRUCT &vs) {
const_cast<IProject::VSTRUCT &>(vs) = std::max(vs, minReq);
CompilerBase::setMinRequiredVersion(vs, Type::getSerialID());
}
};
}
}
RESOLVED!
After digging in g++ 4.2's source code I found out that it needs to now about all types in the complete tree. g++ > 4.2 apparently doesn't need this.
So, the error was in a related class which had a template member with a forwarded specialization. I just included the header instead of forwarding and g++ 4.2 was happy.
Otherwise it is really a non-nice bug not to give an error, but this useless message.
A thunk or trampoline is a piece of code that is added in some implementations of dynamic dispatch to adapt the interface of the base virtual function with respect to the final overrider being used. As you mentioned it is commonly needed to adapt the this pointer in multiple/virtual inheritance (for bases listed after the first non-empty one) and to adapt the resulting pointer/reference with covariant return types.
The error indicates that it is a compiler bug. If you have to use that particular compiler you will need to work around the issue, and that will involve changing your design. You can try to limit the use of multiple/virtual inheritance, reorder the bases in the list or try to play around until you manage to get the compiler to digest that code somehow. If it is a problem when generating the adapter for a covariant return type, consider removing the covariant return and provide an overload (with a different name) that will return the covariant type (i.e. replace covariant return with a non-virtual function returning the most derived type and a virtual function that calls the previous and returns a reference to the base).
Other than those generic hints, without seeing the code you have and the implementation of the compiler there is little else to say.
I am using Xcode 4.4 with mountain lion. I can't seems to understand why non-static member initalization in templates invokes a move constructor for the variable. Is there anyway to overcome this error?
Example Code:
#include <iostream>
#include <atomic>
//
// This class can compile
//
class Working
{
public:
int GetValue() { return value_; }
private:
std::atomic<int> value_{0};
};
//
// This class cannot compile
//
template <typename Ty1>
class NotWorking
{
public:
int GetValue() { return value_; }
private:
std::atomic<int> value_{0}; // <---- error here
};
int main(int argc, const char * argv[])
{
Working working;
NotWorking<int> not_working;
return 0;
}
Xcode 4.4 and Clang throws the error in that line saying:
"Copying member subobject of type 'std::atomic<int>' invokes deleted constructor"
This looks like a clang bug on the open source svn trunk repository. Could you submit a bug report against clang here: http://llvm.org/bugs/ ?
Thanks!
I want to use a boost::ptr_map inside a specific class which stores instances of itself. However, please consider the following example:
#include <boost/checked_delete.hpp>
#include <boost/ptr_container/ptr_map.hpp>
class foo
{
friend void boost::checked_delete<>(foo*);
~foo() {}
};
int main()
{
boost::checked_delete(new foo); // OK
boost::ptr_map<int, foo> foo_map; // error C2248: 'foo::~foo' : cannot access private member declared in class 'foo'
return 0;
}
The error happens at the following line
// verify that types are complete for increased safety
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x; // error C2248
}
What exactly is going on here? Shouldn't it work? I assume that the problem is that templates are defined in the compilation unit they are included in and boost::checked_delete is called from another compilation unit in the implementation source of bosst::ptr_map. So, it's not the same function I declared as a friend.
However, is there a workaround for this problem?
Try this syntax when declaring the friend:
template <class T>
friend void boost::checked_delete(T*);
Here is the start of the huge error message* from GCC, which is the start of the chain of instantiations (usually, and in this case):
In file included from main.cpp:1:0:
main.cpp: In function 'void boost::checked_delete(T*) [with T = const foo]':
Adding
friend void boost::checked_delete<>(foo const*);
makes the code compile.
(*): 13 lines and 3510 characters for 270 chars/line
I have the following code (stripped down version from actual project to reproduce
the issue) that results in a compiler error on RHEL5 (g++ version 4.1.2):
----------- driver (test.cpp)--------------
#include <iostream>
#include <classa.hpp>
#include <func.hpp>
namespace globals {
static int kth(const A& a) {
return kth(a.ival());
}
}
using namespace globals;
int main() {
A a;
std::cout << func(a) << std::endl;
return 0;
}
----------class A (classa.hpp)------------
class A {
public:
A():val(0){}
const int ival() const {return val;}
private:
int val;
};
------- namespace globals (func.hpp) ------
namespace globals {
int kth(const int& c) {
return c;
}
template <class T>
int func(const T& key) {
return kth(key);
}
}
--------------------------------------------
Compiling it using g++ 4.1.2 gives me the following error:
func.hpp: In function ‘int globals::func(const T&) [with T = A]’:
test.cpp:15: instantiated from here
func.hpp:8: error: invalid initialization of reference of type ‘const int&’ from
expression of type ‘const A’
func.hpp:2: error: in passing argument 1 of ‘int globals::kth(const int&)’
Same code compiles and runs perfectly fine on RHEL4 (g++ version 3.4.6)! Any explanations/ideas/suggestions on how to resolve this error(?) on RHEL5 will
be much appreciated!
Edit:
Thanks Sergey. That is the obvious solution that I am aware of already. But I forgot to add that the restriction is that func.hpp cannot be edited (for e.g., its 3rd party write-protected). Any workarounds?
Here's what happens. When the function func() is defined, the compiler doesn't know about the function kth(const A&) yet because it is defined later in the code. So when it encounters a reference to kth() inside func(), it assumes that it is a reference to kth(const int&). Now when func() is actually instantiated, it fails to compile it because T is A, not int. I am not sure why it works in another version of the compiler, but I think it is because it actually starts resolving references when a template function is instantiated, not when it is declared. But this looks like a bug in the older version because with such behavior a function definition changes depending on where it is instantiated from, which is very confusing.
The only way to fix your code that it works with any compiler would be to put the definition of kth(const A&) between kth(const int&) and func() or a forward declaration of kth(const A&) somewhere above func().
Update
With the restriction of not editing func.hpp the best workaround I can think of is to create a custom header file with something like this:
#include <classa.hpp>
namespace globals {
static int kth(const A& a); // defined later, but used by func.hpp
}
#include <func.hpp>
I also don't see why kth(const A&) is defined as static, but used by a global header. I'd rather put it into the classa.cpp and its declaration into the classa.hpp. But this may be some design feature or artifact I am not aware of.