Global `comptime var` in Zig - mutability

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

Related

Use of scoped enum in a class prior to its definition

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.

How to get a reference to the negation of a bool?

For example, if I have a bool value v, I want a reference to !v that can change when v changes. An example use will be:
class A {
bool& isOpen;
A(bool& value): isOpen(value) {}
void f() {
if (isOpen) {
doSomething();
}
}
};
class B {
bool& isClosed;
B(bool& value): isClosed(value) {}
void g() {
if (isClosed) {
doSomething();
}
}
};
int main() {
bool isOpen = true;
A a(isOpen);
B b(negattive_reference_of(isOpen));
a.f(); // doSomething()
b.g(); // do nothing
isOpen = false;
a.f(); // do nothing
b.g(); // doSomething()
}
Is there anyway in C++ to acheive a similar effect?
Under the hood reference is equivalent to a constant pointer to some variable (compiler just gives you a syntax sugar of how to work with such pointers so that they are always initialized).
So you wan't to have the same variable and two different pointers to it, one of which will dereference to true and the other to false. That is obviously impossible.
The OOP -way to do it would be to pass not reference to boolean but some interface to your classes and use implementation that uses same boolean variable:
class IIsOpenProvider
{
public:
virtual ~IIsOpenProvider() = 0;
virtual bool GetOpenValue() = 0;
};
class IIsClosedProvider
{
public:
virtual ~IIsClosedProvider() = 0;
virtual bool GetClosedValue() = 0;
};
class ValueProvider : public IIsOpenProvider, public IIsClosedProvider
{
public:
bool GetOpenValue() override { return isOpen; }
bool GetClosedValue() override { return !isOpen; }
private:
bool isOpen;
};
class A {
IIsOpenProvider& isOpen;
A(IIsOpenProvider& value): isOpen(value) {}
void f() {
if (isOpen.GetOpenValue()) {
doSomething();
}
}
};
class B {
IIsClosedProvider& isClosed;
B(IIsClosedProvider& value): isClosed(value) {}
void g() {
if (IIsClosedProvider.GetClosedValue()) {
doSomething();
}
}
};
// usage
ValueProvider val;
A a(val);
B b(val);

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++ enable, disable class member functions?

Is it possible to enable, disable class member functions?
Situation:
I have a class with 2 types. Each Type has a own constructor. One Type need a function which must not have the other Type.
Example:
class A {
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
const TypeEnum type;
int x;
A(void) : type(TypeEnum::TYPE_1) { }
A(int _x) : type(TypeEnum::TYPE_2) {
x = _x;
}
// function only for Type 2
void A::operator += (const int& n) {
x = x + n;
}
};
int main() {
A test1 = new A();
A test2 = new A(1);
test1 += 5; // compiler error should be here
test2 += 5; // OK
return 0;
}
Is where something possible like this:
class A {
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
const TypeEnum type;
int x;
A(void) : type(TypeEnum::TYPE_1) { }
A(int _x) : type(TypeEnum::TYPE_2) {
x = _x;
}
// Is somethig like this realy impossible
void A::operator += (const int& n) -> enable_if(type == TypeEnum::Type2) { // if not compile error
x = x + n;
}
};
You can use specialization:
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
template<TypeEnum Type>
class A;
template<>
class A<TypeEnum::TYPE_1>
{
public:
A(void) { }
};
template<>
class A<TypeEnum::TYPE_2>
{
public:
A(int _x) {
x = _x;
}
int x;
void operator += (const int& n) {
x = x + n;
}
};
int main() {
A<TypeEnum::TYPE_1> test1;
A<TypeEnum::TYPE_2> test2{1};
test1 += 5; // compiler error should be here
test2 += 5; // OK
return 0;
}
Maybe following may help:
class A {
public:
explicit A(TypeEnum type) : type(type) {}
virtual ~A() {}
protected:
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
const TypeEnum type;
};
class B : public A{
public:
B() : A(TYPE_1) {}
};
class C : public A{
public:
explicit C(int x) : A(TYPE_2), x(x) {}
C& operator += (int n) { x = x + n; }
private:
int x;
};
inheritance is here to reflect your case with a common type. it is not required else.
A thing you can do anyway:
B make_A() { return B{}; }
C make_A(int x) { return C{x}; }
int main() {
auto test1 = make_A(); // B
auto test2 = make_A(1); // C
test1 += 5; // compiler error should be here
test2 += 5; // OK
return 0;
}
Strange that you didn't get compilation error here:
// function only for Type 2
void A::operator += (const int& n) {
x = x + n;
}
I thought you wanted something like:
// function only for Type 2
A& operator += (int n) {
x = x + n;
return *this;
}
Answering on your question - C++ doesn't work like this. Nevertheless you can implement something similar with templates but I suggest not to do it unless it's just a test program.

Callback parameter for lambdas and member functions

I have this function:
void func(boost::function<void(float)> cb){
//do something with cb()
}
It works with lambdas and functions.
But it does not allow me to pass a member function or a lambda defined in a member function.
I tried to cast something like this:
void class::memberFunc() {
void func((void(*)(float))([](float m){}));
}
But it seems like lambda is ignored at calls.
And no idea how to pass a member function too.
Given:
struct T {
T(int x) : x(x) {};
void foo() {
std::cout << x;
}
int x;
};
The object pointer is an implicit first parameter to functions, and this becomes explicit when dealing with boost::function.
You can "hide" it from func by binding it early:
void func(boost::function<void()> cb) {
cb();
}
int main() {
T t(42);
func(boost::bind(&T::foo, &t));
}
Or otherwise you can bind it late:
T t(42);
void func(boost::function<void(T*)> cb) {
cb(&t);
}
int main() {
func(boost::bind(&T::foo, _1));
}
See it working here.

Resources