C++ template class inheritance - c++

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.

Related

MSVC's (seem not perfect) support for constexpr

I am making the naive wheel of type traits's is_base_of. And Here's a minimal demo about my implementation(didn't consider robustness, is_class...).
#include <type_traits>
#include <cstdint>
struct A
{
};
struct B : A
{
};
template
<typename T, typename U>
struct IsBaseOf {
constexpr static bool Test(T* t)
{
return true;
}
constexpr static bool Test(...)
{
return false;
}
constexpr static bool value = IsBaseOf<T,U>::Test(static_cast<U*>(nullptr));
};
int main()
{
static_assert(IsBaseOf<A, B>::value, "Pass");
}
This demo can be compiled by gcc/clang but cannot be compiled by MSVC.
http://rextester.com/ATOC6638
http://rextester.com/IWU81465
When i type it on my laptop's Visual Studio 2015(with update patch 3). It cannot be compiled either, the IDE reminds me that "expression must have constant value" before compiling.
So I wonder how's MSVC support for constexpr, or is my code wrong?
This is almost certainly a bug in MSVC. Especially previous versions had numerous issues with constexpr. Here's just a bunch of them for example. Support for many new features is not all that great yet in MSVC. But it's getting better by the minute. You'll want to always use the latest version to try out this sort of stuff. VisualStudio 2017 compiles this code just fine…
Your code compiles with Visual Studio 2017 (cl version 19.15.26726).
You could try adding /std:c++14 or /std:c++latest compiler switch.

friend function in CUDA C++

I am working on a problem that class A and B are declared in namespace test0 and a friend function f of class A declared in namespace test1. Function f receives a reference of a class B object as the parameter. Here is an simplified example.
namespace test0 {
class B;
}
namespace test1 {
void f(test0::B& b);
}
namespace test0 {
class A {
friend void test1::f(test0::B& b);
};
}
The code works with g++. But nvcc gives the following compilation error.
a.cu:11:22: error: ‘B’ has not been declared
friend void test1::f(test0::B& b);
^
a.cu:11:27: error: ‘void test1::f(int&)’ should have been declared inside ‘test1’
friend void test1::f(test0::B& b);
^
Could you please help me figure out what the problem is? Thank you in advance.
It is important to understand that nvcc isn't a compiler, it is a compiler driver, and in both cases, the code is compiled with gcc and the error is a gcc generated error. If you put that code in a .cc extension file and compile it via nvcc, there will no be no error.
But when compiling CUDA code (in a .cu file in this case), there are some intermediate processing stages between your code and the final g++ pass which compiles it. Under the hood, what is happening is that your code is being transformed by the CUDA C++ front end parser to this:
# 1
# 2
namespace test0 {
# 3
class B;
# 4
}
# 6
namespace test1 {
# 7
void f(test0::B & b);
# 8
}
# 10
namespace test0 {
# 11
class A {
# 12
friend void test1::f(B & b);
# 13
};
# 14
}
compare that to the original friend void test1::f(test0::B& b); and you can see that the namespace has been stripped out by the cudafe++ pass. I don't know why it has been stripped out, but that is the source of the error.
I would recommend reporting this as a bug to NVIDIA if it is a real problem in your application.
After review by the NVIDIA development team, it appears that this may be exposing a bug in the gnu compiler. It is true that the front-end processing by the nvcc toolchain creates a host code (passed to the host compiler) that drops the namespace qualification for b's type, but this should be acceptable because B has already been declared in test0 namespace.
It appears that this has already been reported to the gnu community.
As a supporting data point, clang++ 3.9.1 on Fedora 25 compiles the code reported in the answer given by #talonmies with no errors and no warnings. On my testing up through gnu 6.4.1 on Fedora25, the gnu toolchain still throws an error. I'm not claiming this as a proof point, merely a suggestion that the claim of a bug in gnu might be possibly correct. I am not a language expert. Furthermore I don't wish to start an argument here about that; it's not the purpose of this question or answer.
The NVIDIA development team has taken the issue under review and hopes to have a fix or workaround in a future CUDA release.
In the meantime, the source-level workaround suggested is to use a dummy typedef for B in class A. i.e.:
class A {
typedef B dummy_t;
friend void test1::f(dummy_t & b);
};
UPDATE:
The issue should be resolved in CUDA 10.1.105 (CUDA 10.1)

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.

Is Visual C++ correct when it refuses this template-"dependent" based enum?

Code:
#ifdef _MSC_VER
# pragma warning( disable: 4480 ) // enum base as "nonstandard extension"
#endif
enum ShouldBeFine: char { hola };
enum Choice { a, b, c };
template< Choice c > struct Traits;
template<> struct Traits<a> { typedef char Type; };
template<> struct Traits<b> { typedef wchar_t Type; };
template<> struct Traits<c> { typedef long Type; };
template< Choice c >
struct Blah
{
enum X: typename Traits<c>::Type {};
};
int main()
{}
Only after a Herculean effort to file a bug report with Microsoft, did it occur to me that maybe Visual C++ is correct to refuse it, and g++, which compiles the above fine, is maybe wrong?
EDIT Details: the code fails to compile with Visual C++ 10.0 and with the preview of Visual C++ 11.0. Those compilers spit out some rambling error avalanche beginning with an alleged syntax error. The code compiles fine with MinGW g++ 4.4.1. Dani reports that it compiles fine with CLang. Unfortunately Comeau Online does not support this language feature, so it can't be decided in the way we often did for C++98, just give the code to Comeau.
If I am reading the grammar correctly, you are correct in that this should compile. enum-base is : type-specifier-seq, and type-specifier-seq seems to include pretty much any type name you can think of, including typename Traits<c>::Type. And all three specializations result in Type being integral, which is also required of the enum-base. So That looks kosher to me.
This compiles fine in both clang and g++. In addition, template substitution should occur before the class and the enum inside is created, so it should not matter if its template dependent or not.
This has been fixed in the Visual C++ 11 Beta, released on February 29, 2012.
Note also that the warning you disabled--C4480--has also been fixed, so it is no longer incorrectly emitted in native C++ code when enum class is used.

structure in template class

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.