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(); }
};
Related
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.
class Example{
public:
friend void Clone::f(Example);
Example(){
x = 10;
}
private:
int x;
};
class Clone{
public:
void f(Example ex){
std::cout << ex.x;
}
};
When I write f as a normal function, the program compiles successful. However, when I write f as a class member, this error occurs.
Screenshot:
The error you're seeing is not a root-cause compilation error. It is an artifact of a different problem. You're friending to a member function of a class the compiler has no earthly clue even exists yet,much less exists with that specific member.
A friend declaration of a non-member function has the advantage where it also acts as a prototype declaration. Such is not the case for a member function. The compiler must know that (a) the class exists, and (b) the member exists.
Compiling your original code (I use clang++ v3.6), the following errors are actually reported:
main.cpp:6:17: Use of undeclared identifier 'Clone'
main.cpp:17:25: 'x' is a private member of 'Example'
The former is a direct cause of the latter. But doing this instead:
#include <iostream>
#include <string>
class Example;
class Clone
{
public:
void f(Example);
};
class Example
{
public:
friend void Clone::f(Example);
Example()
{
x = 10;
}
private:
int x;
};
void Clone::f(Example ex)
{
std::cout << ex.x;
};
int main()
{
Clone c;
Example e;
c.f(e);
}
Output
10
This does the following:
Forward declares Example
Declares Clone, but does not implement Clone::f (yet)
Declares Example, thereby making x known to the compiler.
Friends Clone::f to Example
Implements Clone::f
At each stage we provide what the compiler needs to continue on.
Best of luck.
I dont understand the behaviour of this snippet: (compiled with clang++ 3.0)
#include <iostream>
using namespace std;
class Base {
public:
virtual void bar() {}
bool foo = false;
};
class Derived : public Base{
public:
Derived() { Base::foo = true; }
};
int main() {
Derived d;
Base b(d);
cout << b.foo << endl; // prints 0
// prints 1 if "virtual void bar() {}" is removed
}
Why does the function Base::bar() have any effect on the copying of Base::foo ?
Your problem looks similar to the one reported as a bug here in the official bugzilla for the llvm project.
As you can see is a recognized bug and it's been patched in the newer versions of Clang, you should switch to newer version of the frontend to fix this issue; in the bug report is also specified the exact revision of clang that is offering a patch for this issue.
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.
template<typename T> struct A {
auto func() -> decltype(T::func()) {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
Seems pretty simple to me. But MSVC fails to compile.
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'func' : is not a member of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see declaration of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(4): error C3861: 'func': identifier not found
Even though the compiler will happily accept calling the function. The below sample compiles fine.
template<typename T> struct A {
void func() {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
I've got the same issue trying to use any types from the template argument.
template<typename T> struct A {
typedef typename T::something something;
};
class B : public A<B> {
typedef char something;
};
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'something' : is not a member of 'B'
Whereas class B clearly defines a type called "something". The compiler is perfectly happy to call functions on an object of type T, T& or T*, but I can't seem to access any types from T.
You are trying to use T::func before it was declared. That's why the compiler shouts at you. Notice that when you derive from a class, the class is generated if it comes from a class template. And the implicit generation of the class (which is called implicit instantiation) necessiates the generation of declarations for all its members (so the compiler knows the sizeof value of the class, and can perform lookup into it).
So it also instantiates the declaration auto func() -> decltype(T::func()) and surely fails here.
There seem to be several issues with your code, one of which looks like a VS10 bug.
You're calling T::func() from A without casting A to T, this is needed as part of CRTP since A doesn't derive from T. -- FixL return static_cast<T*>(this)->func();
What you're passing to decltype looks like a static function invocation while func is in fact an instance function. Since decltype doesn't actually run the function you should do something like this decltype(static_cast<T*>(nullptr)->func())
func is private in B and can't be called from A -- Fix: change A to be a struct
This looks like a bug in VS10, even after all these fixes I get an error that you're trying to use an undefined class B in the decltype.
As a workaround can you refactor func out into a base class? (now we need two template parameters, one for casting to and one for decltype thus creating a new idiom CRTPEX)
struct Base {
void func() { }
};
template<typename T, typename U> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<U*>(this)->func();
}
};
struct B : public A<Base, B>, public Base {
};
I see that g++ also chokes on this decltype can anyone confirm that this is a defect? If so I will open a bug for Microsoft. It is my understanding that the following code is valid but neither g++ nor VC10 compile it.
template<typename T> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<T*>(this)->func();
}
};
struct B : public A<B> {
void func() {}
};
First, I think that the close-to-proper code is:
template<typename T> struct A {
auto func()
-> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
As Motti pointed out. However that still fails, and I think for the reason that the return type of the base has to be known when B is declated to inherit from A<B>, but since B is not defined yet, it becomes a chicken and egg problem.
However, it may be finally be possible in C++1y by using simply auto (without decltype), I tried with gcc-4.8.2
template<typename T> struct A {
auto func()
//c++1y// -> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
This compiles (c++ -std=c++1y) and runs:
int main(){
B b; b.func();
}
Two disclaimers: I don't know why this works. I don't know how standard it is.