Forward declaration inside a namespace - c++

I've encountered a strange problem when trying to compile my code in Visual Studio (2010); here's an isolated (and simplified) example:
class A
{
public:
enum {
VALUE = 0
};
};
namespace ns
{
class A;
class B
{
public:
B(int val = ::A::VALUE) // this line
{}
};
class A : public ::A
{
public:
};
}
This gives the following error: error C2027: use of undefined type 'ns::A'. Is it a bug in VS or am I doing something wrong?
Update: this appears to be a bug specific to Visual Studio. Here's a workaround suggested on Microsoft Connect:
class B
{
public:
typedef ::A A1;
B(int val = A1::VALUE)
{}
};

This is a bug in VC10. Your ::A class name is fully qualified, and the definition of A in the global namespace is visible to the compiler. Besides, GCC 4.7.2 compiles this without problems.

Related

Error with C++ module code containing a class hierarchy involving a template class and a friend class

I'm getting a 'base class undefined' error in some module-based C++ code I'm writing. I've reduced it to the following MCVE. The non-module equivalent compiles fine.
I don't understand why the modularized code here fails. Please could someone explain why I'm getting the error and how, if possible, to fix it.
Here's the module interface unit -
// mcve.ixx
export module mcve;
export class X
{
friend class F; // (1)
};
export
template<typename T>
class A
{
};
export class B: public A<X>
{
};
// (2)
export class F: public B
{
};
and the cpp file showing where the compiler error is reported.
// main.cpp
import mcve;
int main()
{
// X x; // (3)
// A<X> ax; // (4)
// F f; // (5)
B b; // error C2504: 'B': base class undefined
}
Interestingly, removing either of the friend class F; at (1) or the whole class F declaration at (2) results in successful compilation.
Equally, uncommenting either of (3), (4) or (5) also works.
This is with Microsoft Visual Studio 2022 v17.2 (Platform toolset v143)(CL version 19.32.31328) and either /std:c++20 or /std:c++latest.

Proper use of undefined type in template class inheriting from abstract class

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.

Get pointer to class method with 'using' keyword

I'm using Visual Studio 2010.
Why can't I get a pointer to a class method which was "upgraded" to public in a child class?
The following code does not compile:
#include <iostream>
#include <functional>
class Parent {
protected:
void foo() {
std::cout << "Parent::foo()\n";
}
};
class Child : public Parent
{
public:
//void foo() { Parent::foo(); } //This compiles
using Parent::foo; //This does NOT compile
};
int main() {
Child c;
std::function < void () > f = std::bind(&Child::foo, &c);
f();
return 0;
}
It gives the error:
error C2248: 'Parent::foo' : cannot access protected member declared in class 'Parent'
It compiles here.
I think you just forgot to add the C++11 option in you compiler.
For example, with gcc it's -std=c++11 or -std=gnu++11.
EDIT : It seems from here that using alias declaration are not implemented in any Visual Studio version.
In fact, here some people talks about a compiler bug.
The weird thing here is:
c.foo(); // this works fine
std::function < void () > f = std::bind(&Child::foo, &c); // this won't compile
For some reason, Visual Studio won't let you take the address of foo, even though it is a public member of Child declared using plain old C++03 syntax.
std::function<void()> f = std::bind(&Child::foo, &c); // won't compile
auto fp = &Child::foo; // also won't compile
Directly calling the function still works fine:
c.foo(); // compiles OK
Curiously, this means you use VS2010's partial C++11 support to work around a flaw in its C++03 support, by using a lambda to achieve the same effect that your bind expression would have had:
std::function<void()> f = [&c]{ c.foo(); }; // compiles OK!
This code compiles with g++ 4.8.1. Are you using C++11? I get the following output when I run it:
Parent::foo()
In pre c++11,
this 'using' allows to not hide Parent::foo in case like these:
class Parent
{
protected:
void foo() {}
};
class Child : public Parent
{
using Parent::foo; // without this, following code doesn't compile.
public:
// foo(int) hides Parent::foo without the 'using'
void foo(int) { return foo(); }
};

template private inheritance in vc++10 is not accessible

The following code compiles using GCC 4.4.6 and Comeau 4.3.10.
#include <iostream>
struct A { int name; };
template<typename T> struct C : T { using T::name; };
struct B : private A { friend struct C<B>; };
int main()
{
C<B> o;
o.name = 0;
}
It gives the following error in VC++10:
main.cpp(4): error C2877: 'A::name' is not accessible from 'A'
main.cpp(10): error C2247: 'A::name' not accessible because 'B' uses 'private' to inherit from 'A'
What's a good cross-compiler workaround that allows o.name = 0;?
Note: Adding using A::name to B takes care of the problem, but publishes the A::name member to everyone, whereas it should only be visible to a particular template instantiation, namely C<B>.
Work around is what #kerrekSB suggested, add using A::name; in class B:
struct A { int name; };
template<typename T> struct C : T { using T::name; };
struct B : private A {
using A::name;
friend struct C<B>;
};
your initial example didn't work cause class A is private to B and class C<B> is friend of B but when you access member name from object of C<B> , line using T::name; creates problem since the class B doesn't has any member name in it. it's scope search which find the member name when you try to access it via object of class B
Edit :
Adding using A::name to B takes care of the problem, but publishes the
A::name member to everyone, whereas it should only be visible to a
particular template instantiation, namely C
if that's the case , then simply declare statement using A::name; in private section in class B i.e
struct B : private A {
protected: using A::name;
public:
friend struct C<B>;
};
There seems to be a fundamental difference in visibility considerations between gcc and VC++ when using member using-declarations; check this simplified example without templates:
struct A { int name; };
struct B: private A { friend struct C; };
struct C: B {using B::name; };
int main()
{
C o;
o.name = 0;
}
It will compile on gcc but not on VC++ (with basically the same error as in the question). Will have to consult the standard on who is doing it right...

c++ compilation error

i got a compile error which i do not understand.
i have a h/cpp file combination that does not contain a class but just defines some utility functions. when i try to use a struct that is defined in another class i get the error:
error C2027: use of undefined type 'B::C'
so, stripped down to the problem, the h-file looks like this
namespace A {
void foo(B::C::SStruct const & Var);
}
the definition of SStruct is in a class which is in another h-file, that is of course included.
namespace B {
class C {
public:
struct SStruct { };
};
}
the strange thing is, i can use this struct in other classes fine, it just seems to be related to this one h-file which contains just utility functions.
what am i missing here?
thanks!
After correcting missing semicolons etc. this compiles:
namespace B {
class C {
public:
struct SStruct { };
};
}
namespace A {
void foo(B::C::SStruct const & Var);
}
Obviously, if the order of the two namespaces were switched, this would not work. Possibly you are #including your headers in the wrong order. If this is the error, that's bad design - you should not allow header order to matter in your code.
I assume you meant "class C", not "Class C".
struct SStruct is private to class C (private being the default visibility of class members).
As such, it is not visible outside class C and its friends, which does not include A::foo().
Class C {
struct SStruct { };
}
==>
class C {
public:
struct SStruct { };
};
Your class is missing a semicolon after the definition. It should be:
namespace B {
class C {
public:
struct SStruct { };
}; // <=== Here
}