static constexpr function different than global? - c++

I cannot understand why static constexpr behaves differently then global constexpr. What am I doing wrong? Compiler error is not particularly helpful:
prog.cpp:20:17: error: ‘static constexpr int Bar::foo(const char*)’ called in a constant expression
B = Bar::foo(s)
^
prog.cpp:20:17: error: enumerator value for ‘B’ is not an integer constant
code is as follows:
#include <iostream>
constexpr int foo(const char* v)
{
return v[0];
}
struct Bar
{
static constexpr int foo(const char* v)
{
return v[0];
}
static constexpr const char* s = "abc";
enum
{
A = ::foo(s),
B = Bar::foo(s)
};
};
int main()
{
int a[Bar::A];
a[0] = Bar::A;
}

This is because the enum is part of the class declaration, whereas the definitions of the functions inside the class are logically deferred until after the class declaration. This means that as far as the enum is concerned, it can't see the definition of B::foo, and therefore it can't use a call to it as a constant expression. You can see this by putting the enum after the class:
#include <iostream>
constexpr int foo(const char* v)
{
return v[0];
}
struct Bar
{
static constexpr int foo(const char* v)
{
return v[0];
}
static constexpr const char* s = "abc";
};
enum Enum
{
A = ::foo(Bar::s),
B = Bar::foo(Bar::s)
};
which gives no error.

Related

Accessing an inline function through a const member variable

I wanted to understand how the inline member variable work while accessing it through a const member variable.
Each time I try doing so, I get an error!
This is what I am trying
#include <iostream>
#include <string>
using namespace std;
class A{
public:
A()
{
_uuid = 0;
}
~A();
void setUUID(int n) { _uuid = n; }
inline int getUUID(){ return _uuid;} const
int getUUID1() const { return _uuid;}
int getUUIDsmart()const
{
return _uuid;
}
private:
int _uuid;
};
class B {
public:
B(){}
~B();
void fun1(const A *obj)
{
cout<<obj->getUUIDsmart()<<endl; //works fine
cout<<obj->getUUID1()<<endl; //works fine
cout<<obj->getUUID()<<endl; //error
A *obj1 = const_cast<A *>(obj);
cout<<obj1->getUUID()<<endl; //works fine
}
};
int main()
{
B *b = new B;
A *a = new A;
a->setUUID(12);
b->fun1(a);
}
I am able to get my code work through
const_cast
But I am interested in knowing why do i get an error in the inline function if I try accessing it through a const member function?
Update: FIX
My bad. I had the placement of const messed up!
Thanks to #bruno
inline int getUUID() const { return _uuid; }
//correct syntax. i placed the const at the end
[note : I use the first version of the question]
you place wrongly your const :
inline int getUUID(){ return _uuid;} const
int getUUID1(){ return _uuid;} const
int getUUIDsmart()const
is in fact
inline int getUUID(){ return _uuid;}
const int getUUID1(){ return _uuid;}
const int getUUIDsmart()const
I just moved the const on the right line for readability reason
You wanted
inline int getUUID() const { return _uuid;}
int getUUID1() const{ return _uuid;}
in your version none of getUUID1 nor getUUID are const so you cannot apply them on a const instance
There is no link at all with the fact your methods are inline or not.
Note :
cout<<obj->getUUID1()<<endl; //works fine
it doesn't

rvalue qualified method and const expression

How can I make a const rvalue in a natural way?
Here is a simple example :
struct A {
void f() &&{} // 1
constexpr bool f() const &{return true;} // 2
constexpr bool f() const &&{return true;} // 3 really usefull?
};
int main() {
static_assert(A{}.f()); // does not compile because call 1 instead of 3
constexpr A a;
static_assert(a.f());
}
Why does the first static_assert() call 1 instead of 3?
The issue here is A{} doesn't give you a const A, it just gives you an A so 2 gets called since it is callable on a non const rvalue.
If you want 4 to be called you need to make a const A and you can do that using an alias declaration. If you have using A_const = const A; then A_const{} gives you a const A and A_const{}.f() will call 4 instead of 2.
Essentially what it does is static_assert(const A{}.f());, but since syntactically you can't write it that way we need to using declaration to give us a single word type that is a const A.
Additionally you could rewrite
static_assert(A{}.f());
as
static_assert(std::add_const_t<A>{}.f());
and also get a const A rvalue.
The question is, how can I make rvalue object works on a const expression
Another way can be through a constexpr function returning an A const
#include <iostream>
struct A
{
std::size_t f() & { return 1u; }
std::size_t f() && { return 2u; }
constexpr std::size_t f() const & {return 3u; }
constexpr std::size_t f() const && {return 4u; }
};
constexpr A const foo ()
{ return {}; }
int main()
{
static_assert( foo().f() == 4u, "!" );
}
Maybe this does what you want?
struct A {
constexpr bool f() &&{return true;} // 1
constexpr bool f() const &{return true;} // 2
constexpr bool f() const &&{return true;} // 3 really usefull?
};
int main() {
static_assert(A{}.f()); // does not compile because call 1 instead of 3
constexpr A a;
static_assert(a.f());
}

C++ Force const-ness of lvalue in initializer expression

I would like the compiler to enforce const-ness of an lvalue (non-reference) but don't know if this is possible in C++. An example:
int foo() { return 5; }
int main() {
// Is there anything I can add to the declaration of foo()
// that would make the following cause a compile-error?
int a = foo();
// Whereas this compiles fine.
const int a = foo();
}
This is not really possible with something like an int because you need to give access to read the int and if they can read the int then they can copy it into a non-const int.
But from your comments it sounds like what you have in reality is not an int but a more complex user defined type, some sort of container perhaps. You can easily create an immutable container. This container could be a wrapper, or alternative implementation of your existing container. It then doesn't matter if the caller uses a const or non-const variable it is still immutable.
class MyClass {
std::vector<int> data;
public:
MyClass(size_t size) : data(size) {}
int& operator[](size_t index) { return data[index]; }
int operator[](size_t index) const { return data[index]; }
size_t size() const { return data.size(); }
};
class MyClassImmutable {
MyClass mc;
public:
MyClassImmutable(MyClass&& mc) : mc(std::move(mc)){}
int operator[](size_t index) const { return mc[index]; }
size_t size() const { return mc.size(); }
const MyClass& get() const { return mc; }
};
MyClassImmutable foo() {
MyClass mc(100);
mc[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
MyClassImmutable mci = foo();
std::cout << mci[10] << "\n"; // Can read individual values
//mci[10] = 4; // Error immutable
func(mc.get()); // call function taking a const MyClass&
}
Live demo.
Of course there is nothing to stop the caller from copying each and every value from your immutable container and inserting them into a mutable container.
Edit: An alternative approach might be to return a smart pointer-to-const. The only downside is you have to pay for a dynamic memory allocation:
std::unique_ptr<const MyClass> foo() {
auto mc = std::make_unique<MyClass>(100);
(*mc)[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
auto mc = foo();
std::cout << (*mc)[10] << "\n"; // Can read individual values
//(*mc)[10] = 4; // Error const
func(*mc); // can pass to a function taking a const MyClass&
}
It's not possible. foo() has no way of knowing about the type of the left hand side of the assignment, because when the assignment itself happens, foo() is already evaluated. The best you could hope for is to change the return value, to try and cause a type-based error on the initialization:
#include <type_traits>
struct my_int {
const int m;
template<typename T, typename std::enable_if<std::is_const<T>::value, T>::type* = nullptr>
constexpr operator T() const {return m;}
};
constexpr my_int foo() { return {5};}
int main() {
const int a = foo();
int b = foo();
}
Live example
But this will also not work, because the typename in the template will never be substitued by a const-qualified type (in this specific case, it will be int for both lines in main()).
As the following is possible
const int x = 4;
int y = x;
the C++ language will not provide such a mechanism.
Remains making a int const by a macro mechanism.
#define int_const_foo(var) const int var = ___foo()
int_const_foo(a);
Drawback: foo cannot be hidden, and the syntax is no longer C style.

Non-const used in a constexpr : what does the standard say?

What does the C++11 iso standard say about such an expression :
class MyClass
{
public:
constexpr int test()
{
return _x;
}
protected:
int _x;
};
_x is a non-const used in a constexpr : will it produce an error, or will the constexpr be simply ignored (as when we pass a non-const parameter) ?
It's perfectly fine, though somewhat useless:
constexpr int n = MyClass().test();
Since MyClass is an aggregate, value-initializing it like that will value-initialize all members, so this is just zero. But with some polish this can be made truly useful:
class MyClass
{
public:
constexpr MyClass() : _x(5) { }
constexpr int test() { return _x; }
// ...
};
constexpr int n = MyClass().test(); // 5
If the expression does not resolve to a constant expression, then it cannot be used as such. But it can still be used:
#include <array>
constexpr int add(int a, int b)
{
return a+b;
}
int main()
{
std::array<int, add(5,6)> a1; // OK
int i=1,
int j=10;
int k = add(i,j); // OK
std::array<int, add(i,j)> a2; // Error!
}

Using non-const variable inside constexpr?

Consequently to a previous question about const/non-const with ternary operator, is the following test function ok regarding to the C++11 standard :
template<bool UseConst> class MyClass
{
public:
constexpr bool test()
{
return (UseConst) ? (_constvar) : (_var);
}
protected:
int _var;
static const int _constvar;
}
The whole problem, is that _constvar is const, and _var is non-const. I would have to access these 2 data depending on the template parameter through the same function, and I would like to have a compile-time function when I use const.
Do the test() function satisfy my requirements ?
You could use SFINAE in order to "specialize" your test function. In other words, you could do something like the following:
template<bool true_false>
struct true_type
{
static char value;
};
template<>
struct true_type<false>
{
static char value[2];
};
template<bool UseConst> class MyClass
{
private:
constexpr int pre_test(const char arg) { return _constvar; }
int pre_test(char (&)[2]) const { return _var; }
public:
constexpr int test()
{
return pre_test(true_type<UseConst>::value);
}
protected:
int _var;
static const int _constvar;
};
Now, when you call MyClass::test, if UseConst is false, test will degrade to a run-time function, but when UseConst is true, you will get a compile-time function.