Use of scoped enum in a class prior to its definition - c++11

I'm trying to understand how the compiler handles this code. The two class methods both reference the enumeration before it is defined, but only one generates a compile error. I'm using GCC 9.2:
class Test {
public:
Test() {}
~Test(){}
//gcc seems to be happy with this...
int Foo()
{
TestState v = TestState::Value1;
if (v == TestState::Value1) {
return 0;
} else if (v == TestState::Value2) {
return 1;
}
}
// ... but it doesn't work when used as a parameter
int Bar(TestState v)
{
if (v == TestState::Value1) {
return 0;
} else if (v == TestState::Value2) {
return 1;
}
}
private:
enum class TestState:bool
{
Value1 = false,
Value2 = true
};
};
In this case, the function Foo compiles fine under gcc 9.2, but Bar does not:
enum.cpp:18:13: error: ‘TestState’ has not been declared
int Bar(TestState v)
^
enum.cpp: In member function ‘int Test::Bar(int)’:
enum.cpp:20:13: error: no match for ‘operator==’ (operand types are ‘int’ and ‘Test::TestState’)
if (v == TestState::Value1) {
^
enum.cpp:22:20: error: no match for ‘operator==’ (operand types are ‘int’ and ‘Test::TestState’)
} else if (v == TestState::Value2) {
Why does gcc seem to accept the usage of the enum prior to definition in one instance but not another? I understand that the enum should be declared before these functions, but why does Foo compile without error?

Maybe you can see this as a lack of declaration of TestState by the time Bar(TestState) is declared. Actually this code can be simplified as below:
struct A {
void f() {} /// fine
void g(B) {} /// not fine
struct B {};
};
int main() {
return 0;
}
This code just can't compile as yours, since by the time g(B) is declared, the compiler needs to look up where the declaration of B is, which cannot be found.
That's when we need Forward Declaration. Add a forward declaration, and you may find compilation successful:
struct A {
void f() {} /// fine
struct B;
void g(B) {} /// fine now
struct B {};
};
int main() {
return 0;
}
It's the same with your code. So add private: enum class TestState : bool; before the public in your code, and it'll compile.

Related

C++ error: using temporary as lvalue when using member variable of container in dervied class

#include<iostream>
class acc{
public:
acc() { aa = 10;}
int aa;
};
class Derv;
class Base{
public:
Base() {}
int a;
virtual acc get_acc() {};
virtual void compare(Derv *v) {}
};
class Derv : public Base {
public:
acc acc_o;
Derv() {}
virtual acc get_acc();
virtual void compare(Derv *v) {
if(v->get_acc().aa = acc_o.aa) {
std::cout<<"Values Match\n";
}
}
};
acc Derv::get_acc() {
return acc_o;
}
int main() {
Base *d1 = new Derv();
Base *v = new Derv();
Derv *v1 = dynamic_cast<Derv *>(v);
d1->compare(v1);
std::cout<<d1->get_acc().aa<<std::endl;
return 0;
}
Above code is giving compiler error when compiled using gcc. Following is the compiler error:
accessor_test.cpp: In member function ‘virtual void Derv::compare(Derv*)’:
accessor_test.cpp:25:40: error: using temporary as lvalue [-fpermissive]
if(v->get_acc().aa = acc_o.aa) {
Not able to understand what is the reason for error? Can someone help me understand the error and possible fix for the same?

Global `comptime var` in Zig

In Zig, I can do this with no problems:
fn foo() void {
comptime var num: comptime_int = 0;
num += 1;
}
But when I try declaring the variable outside of a function, I get a compile error:
comptime var num: comptime_int = 0;
fn foo() void {
num += 1;
}
fn bar() void {
num += 2;
}
error: expected block or field, found 'var'
Zig version: 0.9.0-dev.453+7ef854682
Use the method used in zorrow. It defines the variable in a function (a block works too), then it returns a struct with functions for accessing it.
You can create a struct that defines get and set functions:
const num = block_name: {
comptime var self: comptime_int = 0;
const result = struct {
fn get() comptime_int {
return self;
}
fn increment(amount: comptime_int) void {
self += amount;
}
};
break :block_name result;
};
fn foo() void {
num.increment(1);
}
fn bar() void {
num.increment(2);
}
In the future, you will be able to use a const with a pointer to the mutable value, and the method shown above will no longer be allowed by the compiler: https://github.com/ziglang/zig/issues/7396

Forward declare unscoped enum in class complains private

Why does the following c++11/14 code not work? Here I am forward declaring an enum within the class. Objective is not to have a huge - 100s of values of enums within the class - which makes the class unreadable. I cannot use a separate scoped enum for this - for political reasons.
class A {
public:
// forward declare the enum
enum B : int;
void func (B b) {}
};
// The actual declaration
enum A::B : int {
Val1,
Val2,
};
int main ()
{
// B is unscoped. so I should be able to use it as below?
int a = A::Val1;
}
Compilation Error
tmp.cpp: In function ‘int main()’:
tmp.cpp:13:5: error: ‘A::B Val1’ is private
Val1,
^
tmp.cpp:19:16: error: within this context
int a = A::Val1;
^
But the following code works :
int a = A::B::Val1;
That error appears in G++ but not in Visual C++ and clang. Formally enum's id can be used as namespace, or can be skipped, but last two do skip it by default, while latest g++ enforces it. That's changeable by compiler options. Use of enum class' id is mandatory:
class A {
public:
// forward declare the enum
enum class B : int;
void func (B b) {}
};
// The actual declaration
enum class A::B : int {
Val1,
Val2,
};
int main ()
{
int a = static_cast<int>(A::B::Val1); // no implicit cast
}

std::list::remove_if goes crazy if combined with a generic lambda

I found a problem that I guess is due to a bug in GCC.
Anyway, before opening an issue, I would like to be sure.
Consider the code below:
#include<algorithm>
#include<list>
template<typename U>
struct S {
using FT = void(*)();
struct T { FT func; };
template<typename>
static void f() { }
std::list<T> l{ { &f<int> }, { &f<char> } };
void run() {
l.remove_if([](const T &t) { return t.func == &f<int>; }); // (1)
l.remove_if([](const auto &t) { return t.func == &f<int>; }); // (2)
}
};
int main() {
S<void> s;
s.run();
}
clang v3.9 compiles both (1) and (2) as expected.
GCC v6.2 compiles (1), but it doesn't compile (2).
The returned error is:
error: 'f' was not declared in this scope
Moreover, note that GCC compiles (2) if it is modified as it follows:
l.remove_if([](const auto &t) { return t.func == &S<U>::f<int>; }); // (2)
As far as I know, using an const auto & instead of const T & should not alter the behavior in this case.
Is it a bug of GCC?
Per [expr.prim.lambda]:
8 - [...] [For] purposes of name lookup (3.4) [...] the compound-statement is considered in the context of the lambda-expression. [...]
MCVE:
template<int>
struct S {
template<int> static void f();
S() { void(*g)(char) = [](auto) { f<0>; }; }
};
S<0> s;
Hoisting the compound-statement to the context of the lambda-expression gives a clearly valid program:
template<int>
struct S {
template<int> static void f();
S() { f<0>; }
};
S<0> s;
So yes, this is a bug in gcc.

C++ returning a non-const method in a const method

I came across this weird issue
I have a method that is a const, per se:
void doSomething() const { x(); } and x is a non-const method.
Compiling would result in a discards qualifiers error.
say I turn doSomething to int, and make x return some dummy int, and it turns into:
int doSomething() const { return x(); }
Is it normal that it would compile? it does compile on my compiler, which leads me to think this might be a compiler bug.
The compiler version is: gcc (Debian 4.4.5-8) 4.4.5
class GgWp
{
public:
int doSomething const { return x(); }
int x()
{
num = 5;
return 0;
}
private:
int num;
}
As you can see, x modifies the variable num
Consider this line:
int doSomething() const { return x(); }
If x() is a member function then it must be const or this will not compile on any major standards-compliant compiler. This has nothing to do with whether or not you actually return the value of x() or whether you return anything from doSomething(). You can't run a non-const function from a const function.
If x() is not a member function then this doesn't apply.
The const after the function name refers to the object (this)
, so you should not be able to call x() (if x is not const) from a const method, and return types should make no difference.
If it compiles anyway, either x() is not a member, it's const, or
your compiler is malfunctioning.

Resources