structure in template class - c++

sample code is as follow:
struct TEMP
{
int j;
TEMP()
{
j = 0;
}
};
template<typename T>
class classA
{
struct strA
{
long i;
strA():i(0) {}
};
static strA obj_str;
classA();
};
template<typename T>
classA<T>::classA()
{}
template<typename T>
classA<TEMP>::strA classA<TEMP>::obj_str;
int main()
{
return 0;
}
while compiling this code, I am getting following error:
test1.cpp:32: internal compiler error: in import_export_decl, at cp/decl2.c:1970
Please submit a full bug report,
with preprocessed source if appropriate.
See http://bugzilla.redhat.com/bugzilla> for instructions.
Preprocessed source stored into /tmp/ccUGE0GW.out file, please attach this to your bugreport.
I am building this code at x86_64-redhat-linux machine, and gcc version is gcc version 4.1.2 20070626 (Red Hat 4.1.2-14)
Please note this code was already built with gcc version 3.4.5 20051201 (Red Hat 3.4.5-2) at i386-redhat-linux machine.
Any idea why this is not able to build with gcc 4.1.2.
Thanks in advance.

In any case, your code doesn't make much sense in the following declaration.
template<typename T>
classA<TEMP>::strA classA<TEMP>::obj_str;
Because the T parameter is used nowhere in the declaration. I think you either wanted to write one of the following things:
// definition of static member of template
template<typename T>
typename classA<T>::strA classA<T>::obj_str;
// ... or declaration of static member specialization for `T=TEMP` of template
template<>
classA<TEMP>::strA classA<TEMP>::obj_str;
I suspect it was the first one. For the compiler crash - that surely shouldn't happen in any case :)
Edit: The bug has already been fixed in 4.4.1 at least - i think there is no need for reporting anymore.

I would follow the error report.

Related

MSVC evaluating context (and erroring) without knowing types

This code fails compilation on MSVC because the static_assert fails:
template<class MyType>
struct Test {
static_assert(MyType(5) != MyType(6), "fails");
};
See: https://godbolt.org/z/vUSMHu
Any ideas how MSVC can evaluate this without even knowing what MyType is?
Even more obscure:
template<class MyType>
struct Test {
static_assert(MyType(5) == MyType(6), "succeeds");
static_assert(!(MyType(5) == MyType(6)), "fails");
};
See: https://godbolt.org/z/3631tu
And instantiating it (i.e. giving MyType a type) also doesn't help:
template<class MyType>
struct Test {
static_assert(MyType(5) != MyType(6), "still fails");
};
Test<int> variable;
See: https://godbolt.org/z/yxF4h0
Or a bit more complex: https://godbolt.org/z/68g6yO
Yes, this strange error happens in MSVC 19.10, but it is already not reproducible in MSVC 19.14 and upward. Demo: https://gcc.godbolt.org/z/635Mxdazd
So it is reasonable to assume that it was just a compiler bug.

std::string & as template parameter and abi_tag in gcc 5

Consider the following piece of code (test1.cpp):
#include <string>
extern std::string test_string;
template<std::string &s>
class test{
public:
static void bar(){ }
};
std::string test_string("test string");
void foo(){test<test_string>::bar();}
Now let us switch order of two last lines of code (test2.cpp):
#include <string>
extern std::string test_string;
template<std::string &s>
class test{
public:
static void bar(){ }
};
void foo(){test<test_string>::bar();}
std::string test_string("test string");
Nothing should change. But if you look via objdump to compiled file you will see difference:
objdump -t -C test*.o | grep bar
In one case template test was instantiated as:
test<test_string[abi:cxx11]>::bar()
and in another as:
test<test_string>::bar()
both files are compiled just with
gcc -c test*.cpp
So reference to std::string as template parameter is treated as not tagged if it is just declared extern. And it is treated as tagged after definition.
Some classes in my project are instantiated twice where there should be just one class. It is rather unpleasant.
gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2)
Is it a bug in compiler? Or is it expected behavior?
What can be a workaround?
This is definitely a compiler bug; I can't find the exact bug in GCC Bugzilla but it appears similar to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66971 - though simpler, as it doesn't require the use of thread_local keyword, it may well have the same underlying cause.
As a workaround, it appears that changing the reference template parameter to a pointer will make it work:
template<std::string *s> class test { .... };
void foo(){test<&test_string>::bar();}
Edit: I've filed this bug with gcc as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69621

CUDA linker error with template class

Using CUDA 5.0 on ubuntu with gcc/g++ 4.6, I'm getting errors when linking against CUDA code with templates.
cu_array.cu:
#include "cu_array.hpp"
template<class T>
CuArray<T>::CuArray(unsigned int n) {
cudaMalloc(&data,n*sizeof(T));
}
cu_array.hpp:
#pragma once
template<class T>
class CuArray {
public:
CuArray(unsigned int n);
private:
T* data;
};
main.cu:
#include "cu_array.hpp"
int main() {
CuArray<float> a(10);
}
These compile fine with nvcc -c, but linking with nvcc cu_array.o main.o gives undefined reference to CuArray<float>::CuArray(unsigned int). If I move the contents of cu_array.cu into the header and only build the main, it uses the templates just fine. Or if I remove the templates altogether, the code naturally links fine.
I'm sure there's a simple answer for this. Any ideas?
You haven't instantiated the class in the compilation unit where it is defined, so the compiler doesn't emit any code for the class member function, and linkage fails. This isn't specific to CUDA, this greedy style of instantiation is the compilation/linkage model g++ uses, and lots of people get caught out by it.
As you have found already, the simplest solution is to include everything into the same compilation unit, and the problem disappears.
Otherwise if you explicitly instantiate CuArray::CuArray at the bottom of cu_array.cu like this:
template CuArray<float>::CuArray(unsigned int);
the compiler will emit code where it would otherwise not, and the linkage problem will be fixed. You will need to instantiate every class function for every type you want to use elsewhere in the code to make this approach work.

Curiously Recursive Template Pattern in GCC 3.4 (MoSync to be exact)

I'm currently trying to write an Artemis like game component/entity system in C++. I was planning on getting this system to work with a cross platform tool for writing applications on Android and iOS called MoSync.
Unfortunately MoSync currently uses an old version of GCC and when porting the library that I had been testing in Visual Studio, I got a whole bunch of errors. Most of these I could solve, but there is one bug with templates that I can't get my head around.
I wrote a small example
template <typename T>
struct Base
{
static int type;
};
struct Derived : public Base<Derived>
{
};
template <typename T>
int Base<T>::type(-1);
extern "C" int MAMain()
{
Derived d;
d.type = 0;
}
My library uses the Curiously Recursive Template Pattern for defining Components. This example compiles fine in GCC 4.4 and Visual Studio 2010. However when I try to compile this in MoSync (which uses GCC 3.4.6) I get this linker error
C:\MoSync\workspace\pede\main.cpp: Error: Unresolved symbol '__ZN4BaseI7DerivedE4typeE',
Is there a workaround to get this to work in this compiler, or will I have to find another way to define my Components?
Edit*
In fact I can make this error occur with an even simpler example:
template <typename T>
struct Component {
static int t;
};
template <typename T>
int Component<T>::t(-1);
extern "C" int MAMain()
{
Component<int>::t = 0;
}
Gives this error
C:\MoSync\workspace\Components\main.cpp:9: Error: Unresolved symbol '__ZN9ComponentIiE1tE',
I guess this might not have anything to do with the Curiously Recursive Template Pattern at all. What can I do to get this to compile under GCC 3.4.6?
According to this bug report on the gcc bugtracker, the problem is caused by specifying a default value in the static variable definition. The code should link if you remove the initialisation as so:
int Base<T>::type;
The bug report seems to have been resolved as not a bug. Despite this, your samples compile fine in GCC 4.4.
To work around this, you can use a class type with a constructor that will automatically initialise itself.
Does adding
int Base<Derived>::type(-1);
helps ?
gcc 3.4 is really starting to be old and don't coep well with template sorcery.

C++ template class inheritance

I have been porting some C++ code, which was written long time ago, and is normally compiled with Visual C++ (Visual Studio 7.1 version) and Intel C++ Compiler 11.0, the target platform is Linux (Suse x86-64), with GCC 4.3.2 and Intel C++ Compiler 11.1
The problem is that code like this
FileA.h
template<typename T, int dim>
class A
{
public:
A(){};
~A(){};
protected:
void foo1(){};
}
FileB.h
#include "FileA.h"
template<typename T>
class B : public A<T, 2>
{
public:
B(){};
~B(){};
void foo(){ foo1(); }
}
main.cpp
#include "FileB.h"
int main()
{
B<float> b = B<float>();
}
does not compile on Linux (Intel C++ 11.1, GCC 4.3.2), but perfectly compiles on Windows (Visual C++ 7.1, Intel C++ 11.0), althow it surely must not depend on platform.
GCC tells that if I change foo1() to foo1(T a) it will work (and it does), but I can not change the code, and have to use Intel C++ for final release.
I would be glad if anyone could help with any advice.
foo1 is not a dependent expression so the base class, which is a dependent type, is not used to resolve the foo1 call.
As you can't change the code, you are stuffed. If you could change the code you would need to change the expression to be dependent. Typically this is done by changing it to this->foo1().
This is a well-known problem with templates. It is explained in the C++ FAQ
On gcc 4.4.1 (os is Ubuntu) version I could turn the compile error into a compile warning, by using the -fpermissive option to the compiler.
Edit: The fact that some compiler accept it, doesn't mean it will continue to accept it in future versions.