Wiki

Clone wiki

ConstCPP / Home

Welcome

ConstCPP is C++ with the const modifier on, all of the time. Except when you use mutable instead. Or disable ConstCPP via a pragma to support normal C++ in ConstCPP code.

This is a hacked together compiler patching clang/LLVM 2.9 and is in no way actually tested, rigourously designed, or necessarily useful or usable.

Inspired by a tweet from @tim_angus

    "I've often wondered if const-ness should be the 
    default and removed with a mutable keyword instead"

Examples of ConstCPP

Here's an example of some ConstCPP code:

Local or global scalar variables work as before, except they are constant by default.

void f() {
    int a = 0;         // <- const int a = 0;
    mutable int b = 1; // <-       int b = 1;
    b = 2;
}

Aggregate types work a little differently. To act as before, all fields must be declared mutable, and the variable declarations of struct type must also be declared mutable.

struct Normal {
    mutable int a, b; 
    
    Normal() : a(0), b(0) {}
    ~Normal() {}
};

int f2() {
    mutable Normal n,n2;
    n.a = 1;
    n.b = 1;
    n2  = n; 
    return n2.a + n2.b;
}

Omitting a mutable declarator means the struct contains a non-static const member, which has implications such that we must initialise it explicitly in a constructor initialisation list, and we cannot (without subverting the type system by casting away const-ness in an overload of operator= ) assign one instance of the struct to another variable of the same type.

struct PartMutable {
    int a;
    mutable int b;
    PartMutable() : a(0), b(0) {}
    PartMutable(int a, int b) : a(a), b(b) {}
    ~PartMutable() {}
};

int f3() {
    mutable PartMutable n;
    n.b = 1;
    return n.a + n.b;
}

Methods can be overloaded on the basis of mutable and non-mutable. The default is for a method to be const; the mutable keyword is supported to remove const-ness. The const keyword is still supported, but code with both no-qualifier and a const-qualifier will fail to compile, as the two are now equivalent. The mutable keyword needs added.

extern "C" {
    int printf( char *, ...);
}

struct NotMutable {
    int a, b;
    NotMutable() : a(0), b(0) {}
    NotMutable(int a, int b) : a(a), b(b) {}
    ~NotMutable() {}
    
    int getA() {      printf("Not mutable\n"); return a + 1; }
    int getA() mutable {  printf("Mutable\n"); return a - 1; }
};

int f4() {
    mutable NotMutable n;
    NotMutable n2;
     
    return n2.getA() + n.getA();
}

Overloads can also be done on the basis of mutable vs non-mutable.

int f5(int* p) { return *p; }
int f5(mutable int* p) { *p = 1; return 0; }

int f5() {
    mutable int a = 10;
    int b = 15;
    int r1 = f5(&a);
    int r2 = f5(&b);
    if (r1 == 0 && a == 1 && r2 == 15)
        return 1;
    return 0;
}

Pragmas permit the control of when ConstCPP is enabled or disabled within program source. Normal C++ can invoke ConstCPP defined functions, and vice-versa.

/* Turn ConstCPP off and include existing header */
#pragma CONST_CPP OFF
#include <cstdio>

void sum(int* a, int* b, int* r)
{
    *r = *b + *a;   
}

/* Turn ConstCPP on again */
#pragma CONST_CPP ON

void sum(int* a, int* b, mutable int*  r)
{
    *r = *b + *a + 1;   
}

int main(int argc, char** argv) {
    // Call normal C++ sum
    mutable int a = 2,b =2,r = 0;
    sum(&a,&b,&r);
    // Call ConstCPP sum
    int a2 = 2, b2 = 2;
    mutable int r2 = 0;
    sum(&a2,&b2,&r2);
    
    printf("r(4) == %d, r2(5) == %d\n",r,r2);
    
    return 0;
}

Compiling and Using ConstCPP

It builds just like clang / LLVM. To use the compiler, invoke the clang driver program (clang.exe) with the -ConstByDefault argument e.g.

   clang.exe -ConstByDefault test.cpp

A Windows executable can be downloaded as a 7zip archive

Updated