I have the following code with two levels of inheritance of class templates:
template <typename FIELD>
class Class1
{
protected:
int n;
FIELD data1;
public:
Class1();
virtual ~Class1() {}
};
template <typename FIELD> class Class3;
template <typename FIELD>
class Class2 : public Class1<FIELD>
{
protected:
using Class1<FIELD>::n;
FIELD data2;
public:
Class2();
virtual ~Class2() {}
int Method(Class3<FIELD> &) const;
};
template <typename FIELD>
class Class3 : public Class2<FIELD>
{
protected:
using Class1<FIELD>::n;
FIELD data3;
public:
Class3();
virtual ~Class3() {}
};
template <typename FIELD>
int Class2<FIELD> :: Method(Class3<FIELD> & U) const
{
U = Class3<FIELD>();
int g = U.n;
return g;
}
template class Class2<double>;
I compile this into an object file in Ubuntu using command:
g++ -c -std=c++11 -Wall -Wfatal-errors -o Test.o Test.cpp
and no error whatsoever is generated, the object file is created just fine!
However, when I try to compile the very same code from within Visual Studio using Ctrl+F7, I get C2248 error that reads:
'Class3::n': cannot access protected member declared in class 'Class3'
Is there a bug in one of the compilers? Which one follows standard? Despite my faith in g++, I'm inclined to think that VS is more correct in this case since variable n should be accessed by Class2 only from Class1 (since it is base class for Class2) but not from Class3.
Note that I need to add line friend int Class2::Method(Class3<FIELD> &) const;
within Class3 declaration to bypass C2248 error in VS.
Thanks for all the answers!
Related
Well annoyingly it seems to work in Microsoft C but not other compilers I use.
Especially desirable when using templates. Maybe I don't know the "standards compliant way" to do this, but It is really useful and i want code to compile on gcc, clang, etc.
template<class T, class T1, ... /* messy, verbose */ >
class MyTemplate {
protected:
typedef MyTemplate<T,T1, ... /* messy, verbose */ > SimplerName;
// declare a constructor
SimplerName(int arg) { ... }
};
class SubClass
: public MyTemplate<x,y... /* messy */ >
{
public:
SubClass(int arg, blah, blah) : SimplerName(arg) { ... }
}.
I get serious barfage with gcc and emscripten
In file included from /home/peterk/didi-wasmtest/build/include/artd/Matrix4Base.h:2:
/home/peterk/didi-wasmtest/build/include/artd/../../../artdlib-cpp/vecmath/Matrix4Base.h:91:21: error: expected member name or ';' after declaration specifiers
inline Matrix4Base() {
~~~~~~~~~~~~~~~~~~ ^
The code in header
template<class Real, class Super>
class ARTD_API_ARTD_VECMATH Matrix4ColumnMajorT
: public Matrix4CommonT<Real, Super>
{
public:
typedef Matrix4ColumnMajorT<Real, Super> Matrix4Base;
protected:
inline Matrix4Base() {
SType().setIdentity();
}
inline Matrix4Base(bool asIdentity) {
if (asIdentity) SType().setIdentity();
}
inline Matrix4Base(const Super &src) {
SType().set(src);
}
public:
...
};
This all compiles and runs on Microsoft C but all the constructors declared with the typedef names barf on gcc and clang based compilers.
A place I'm trying to use it where I choose which base class based on a macro, but want the subclass not to have to declare two sets of constructors or use a macro to define them. I tried variants with and without the template arguments. Template arguments are required it seems. This code compiles and generates proper code on MSC from visual studio 2017 but my primary target is gcc and emscripten ( clang )
class ARTD_API_ARTD_VECMATH Matrix4f
#ifdef Matrix4f_RowMajor
: public Matrix4RowMajorT<float, Matrix4f>
#else
: public Matrix4ColumnMajorT<float, Matrix4f>
#endif
{
public:
Matrix4f() : Matrix4Base()
{}
Matrix4f(bool asIdentity) : Matrix4Base(asIdentity)
{}
Matrix4f(const Matrix4f &src) : Matrix4Base(src)
{}
The template name serves as an injected class name inside the scope of the class template itself. This is standard and valid:
template<class T, class T1, ... /* messy, verbose */ >
class MyTemplate {
protected:
typedef MyTemplate SimplerName;
// declare a constructor
MyTemplate (int arg) { ... }
};
Live example
You don't even need the alias for the sub-class:
class SubClass
: public MyTemplate<int, char, bool /* messy */ >
{
public:
SubClass(int arg) : MyTemplate(arg) { }
};
Live example
I'm experiencing a problem accessing a protected class member from a class template derived from another class template. I have three class templates, the second derived from the first, and and third one derived from the second. Specifically,
class1.h:
template <typename T> class class1
{
protected:
T data;
int a;
public:
class1();
void someMethod();
};
class2.h:
#include "class1.h"
template <typename T> class class2: public class1<T>
{
using class1<T>::a;
T otherData;
public:
class2();
};
class3.h:
#include "class2.h"
template <typename T> class class3: public class2<T>
{
using class2<T>::a;
public:
class3();
};
class2.cpp:
#include "class2.h"
#include <iostream>
template <typename T> class2<T> :: class2()
{
std::cout<<"Creating class2 object!"<<std::endl;
a = 2;
}
template class class2<double>;
Finally, class3.cpp:
#include "class3.h"
#include <iostream>
template <typename T> class3<T> :: class3()
{
std::cout<<"Creating class3 object!"<<std::endl;
a = 3;
}
template class class3<double>;
When I compile class2.cpp into an object file, like this:
g++ -c -O3 -std=c++11 -Wall -o class2.o class2.cpp
everything goes well. However, a get an error when compiling class3.cpp in the same way. A following error pops up:
In file included from class2.h:4:0,
from class3.h:4,
from class3.cpp:1:
class3.h: In instantiation of ‘class class3<double>’:
class3.cpp:11:16: required from here
class1.h:9:6: error: ‘int class1<double>::a’ is protected
int a;
^
Replacing using class2<T>::a; with using class1<T>::a; in class3 doesn't help.
What's causing this error exactly and how can I avoid it if I really need to access variable a from within class3? Why is it that the first level of inheritance (class2) doesn't detect any problems, and the second one (class3) does? Thanks for any comments.
NOTE: I tried the same type of inheritance, but without templates and removed both lines containing using, and compilation goes well (access to variable a is now granted in class3). The problem definitely has to do with templates.
Your class2 definition is the same as the following:
template <typename T> class class2: public class1<T>
{
private: // default section
using class1<T>::a;
T otherData;
public:
class2();
};
It is because private is the default section for the members of classes. So the a member becomes private here and can't be inherited by the class3. You should explicitly place using class1<T>::a; statement in protected or public section of the class2 definition:
template <typename T> class class2: public class1<T>
{
T otherData;
protected: // <-- added
using class1<T>::a;
public:
class2();
};
Now it can be accessed from the class2 derived classes (including class3).
I have a header file (say the_foo.h) which defines/declares the following classes:
// \file the_foo.h
class FooBase
{
virtual size_t bar_size() = 0;
};
template<class Bar>
class Foo : public FooBase
{
size_t bar_size() { return sizeof(Bar); }
};
class TheBar; // TheBar forward declaration
class TheFoo : public Foo<TheBar>
{
};
Compiling with MS vc14 (Visual Studio 2015), I notice the following behaviors:
Any cpp file which includes the_foo.h and defines TheBar, eg:
#include "the_foo.h"
class TheBar {}; // TheBar definition
will compile just fine. However,
Any cpp file which includes the_foo.h and DOES NOT DEFINE TheBar, eg:
#include "the_foo.h"
fails to compile with error: the_foo.h(11): error C2027: use of undefined type 'TheBar'
The cpp file compiled above contains one single line: inclusion of the header, no more code.
Removing the virtual member function declaration virtual size_t bar_size() = 0; does fix the error.
Thanks to answer from Sam Varshavchik, this code compile fine using gcc 5.3.1, so this issue is clearly compiler specific.
My questions are:
Why does compilation fail in case (2), when TheBar is forward declared only ?
Is there any way to make case (2) compiling successfully under vc14, i.e. without an explicit definition of TheBar, which class I need to keep opaque in some cpp files ?
PS: I edited the code sample of this question in order to make clear what actually causes the issue described in the question. The original code sample (which is quoted in the answer from Sam Varshavchik) may indeed have misleaded on the actual cause of the issue and, consequently, leaded to answers and comments out of the question scope.
Your test case compiles without issues with gcc 5.3.1:
$ cat t.C
class FooBase
{
public:
FooBase() {}
virtual ~FooBase() {}
};
template<class Bar>
class Foo : public FooBase
{
public:
Foo() { sizeof(Bar); bar = new Bar; }
~Foo() { sizeof(Bar); delete bar; }
Bar* bar;
};
class TheBar;
class TheFoo : public Foo<TheBar>
{
public:
TheFoo();
~TheFoo();
};
[mrsam#octopus tmp]$ g++ -c -o t.o t.C
[mrsam#octopus tmp]$
The answer here appears to be "you're using an old C++ compiler that does not correctly compile this".
The compiler searches for a definition of the class TheBar when you try to construct or delete it in the constructor and destructor of the Foo class. It means it needs the implementation at that point, otherwise it has no idea what to do.
If make the following example:
The first header:
// foobase.h
class FooBase
{
public:
FooBase() {}
virtual ~FooBase() {}
};
template<class Bar>
class Foo : public FooBase
{
public:
Foo() { bar = new Bar; }
~Foo() { delete bar; }
private:
Bar* bar;
};
class TheBar;
class TheFoo : public Foo<TheBar>
{
public:
TheFoo() {};
~TheFoo() {};
};
The next header
// thebar.h
class TheBar {};
And the following main file:
// foo_main.cxx
// #include "thebar.h" // Including this include makes the program run
#include "foobase.h"
int main()
{
TheFoo thefoo;
return 0;
}
Then your compiler will tell you what is wrong (only first error shown):
./foobase.h:14:32: error: allocation of incomplete type 'TheBar'
Foo() { bar = new Bar; }
Including thebar.h will solve the problem.
I am not able isolate this error in a small sample to demonstrate here, but the even the error message is so self-contradicting that maybe one can have an idea if this is a bug or not, without testing.
I have a struct that is (presumably, publicly) deriving another one, yet clang insists this is implicitly private inheritance:
error: 'next' is a private member of 'base'
note: constrained by implicitly private inheritance here
struct derived_temp <key> : base <derived>
while g++ compiles fine. I have only changed the actual names of the classes to make messages more readable. The code looks like this:
template </*...*/>
struct base : //...
{
private:
//...
public:
template <typename I> I next(I i) const { return /*...*/; }
//...
};
template <typename /*...*/>
struct derived_temp;
struct key { /*...*/ };
using derived = derived_temp <key>;
template <>
struct derived_temp <key> : base <derived>
{
//...
};
I have tried to keep the form of the code exactly the same as in my project, only changing names and commenting out parts of it.
The error is caused by attempting to call function next() on a temporary object of type derived.
My only explanation is that this may be a bug of clang (yet, I cannot reproduce it in a small sample) that forces me to change
struct derived_temp <key> : base <derived>
to the more explicit
struct derived_temp <key> : public base <derived>
Any idea?
Code:
struct T1 {
int x;
};
struct T2 : T1 {
int y;
};
int main( int argc, char * argv[] ) {
T2 t2;
t2.x = 3;
return t2.x;
}
Building/running:
~ clang blah.cc -o blah; ./blah; echo $?
3
~ clang blah.cc -std=c++11 -o blah; ./blah; echo $?
3
In short: defaults to public inheritance.
I spent a little more time on this to get it closer to the OPs code; this is what I put together (please forgive the typos; I'm using an airgapped machine to test this out):
template <class T>
struct base {
T x;
template <typename I> I blah( I i ) const { return i + x.k.y; }
}
template <class T>
struct derived_temp;
struct key { int y; };
using derived = derived_temp<key>;
template <>
struct derived_temp<key> : base <derived> {
int z;
key k;
};
int main( int argc, char * argv[] ) {
derived d;
d.x = 1;
d.k.y = 2;
d.z = 3;
return 0;
}
Built with:
~ clang --version
clang version 3.4 (tags/RELEASE_34/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
~ clang++ test.cc -o test -std=c++11
I get two basic errors (I'm not quoting the full thing since I'd have to manually type it all):
test.cc:3:5: error: field has incomplete type 'derived_temp<key>'
test.cc:21:5: error: no member named 'x' in 'derived_temp<key>'
As I stared at this, trying to understand both your motivation/intent as well as what the errors said, it occurs to me you're attempting to do circular inheritance to define things in a circular fashion that may not even be possible.
Something is a little off there. Structs should use public inheritance by default. Forget the templates for a moment and the using directive.
Test with the simplest code which sets up your suspected fail case:
struct Base
{
int i;
};
struct Derived : Base
{
};
Now try access i from an instance of Derived. If that works, and it should, start to add features until it has all the same kinds of components as your original code.
Right now I don't have clang to test it myself. So I'm just suggesting a way forward.
I have created a template class(TBase) that defines another class(BaseUDT) within its body.
#pragma once
template<class T>
class TBase
{
public:
class BaseUDT
{
public:
int a;
};
T m_base;
};
Now, i create a class(TDerived) that derives from TBase.
template<class T>
class TDerived : public TBase<T>
{
public:
T m_derived;
BaseUDT m_baseUDT;
};
This code compiles on Visual Studio but when I try compiling it on Xcode on a Mac machine, it throw compile errors. Using TBase::BaseUDT doesn't work either.
I have been trying to go through the ISO c++ docs but still haven't found anything relevant so far.
Its name is dependent - declare it like so:
template<class T>
class TDerived : public TBase<T>
{
public:
T m_derived;
typename TBase<T>::BaseUDT m_baseUDT;
};