The class TestConst has a member set of type std::function<void(double)>.
The setter method is marked as const but it still modifies the internal private variable m_value.
class TestConst {
public:
void setter(double v) const {
set(v);
}
private:
double m_value = 1;
std::function<void(double)> set = [this](double v) {m_value = v;};
};
Why does the compiler (g++ 10.2) allows that without any errors or warnings?
The capture of this isn't const, and the member isn't modified by *this but through an indirection.
This is the same situation:
class TestConst {
public:
void setter(double v) const {
sneaky.set(v);
}
private:
double m_value = 1;
struct
{
TestConst* that;
void set(double v) const { that->m_value = v; }
} sneaky{ this };
};
Related
I have a template:
template<typename T>
struct Parameter {
T value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
// Fix this->value (make this->value const)
}
void print() { std::cout << value << std::endl; }
};
and I would like at some point after initialization to 'const-ify' the value variable
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance.value = 2.3; // Not Allowed, throws error
Is it possible to do so and how?
If you want to maintain the same interface, and marshalling access to value through accessors is something you want to avoid, then you could isolate the "fixable" feature in its own dedicated type that implicitly converts to/from T:
template<typename T>
class fixable {
bool fixed_ = false;
T val_;
public:
fixable() = default;
fixable(T v) : val_(v) {}
fixable(const fixable&) = default;
fixable(fixable&&) = default;
operator const T&() const {
return val_;
}
fixable& operator=(const T& v) {
if(fixed_ ) {
throw std::runtime_error("Fixable has been fixed");
}
val_ = v;
return *this;
}
void fix() {
fixed_ = true;
}
};
You would then replace the T member with a fixable<T> within Parameter:
template<typename T>
struct Parameter {
fixable<T> value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
value.fix();
}
void print() { std::cout << value << std::endl; }
};
The main function from your question can remain exactly as-is.
You can use something like this:
Similar to abowe answer but with boolean inside the Parameter struct
template<typename T>
struct Parameter {
Parameter(std::string name, T value) : name(name), value(value), bFixed(false) {}
void fix() {
bFixed = true;
}
void print() { std::cout << value << std::endl; }
Parameter& operator=(const T& oValue)
{
if (bFixed)
{
throw std::runtime_error("Error fixed value..");
}
value = oValue;
return *this;
}
std::string name;
private:
bool bFixed;
T value;
};
int main()
{
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance = 2.3; // Not Allowed, throws error
}
You cannot change a member variable from const to non-const. However, you can create a new object in which it is const. For example:
template<typename T>
struct example {
T value;
example<T const> fix() && {
return {value};
}
};
int main(){
auto x = example<int>{1};
x.value = 4; // OK
auto y = std::move(x).fix();
y.value = 7; // error: assignment of read-only member
}
The presence of && forces the use of std::move which makes it obvious that x should no longer be used.
Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
is there any generic way to take an existing class, and "constify" it by removing all non-const functionality?
One possible workaround is to create a wrapper class that holds an instance of the class and only gives access to a const reference to it.
template<class T>
class Immutable {
public:
template<typename... Args>
Immutable(Args&&... args) : instance(forward<Args>(args)...) {
}
operator const T&() {
return instance;
}
const T& get() const {
return instance;
}
private:
Immutable& operator=(const Immutable& other) = delete;
T instance;
};
Suppose you have a mutable class Class:
class Class {
public:
Class() : m_value(0) {
}
Class(const Class& other) : m_value(other.m_value) {
}
Class(int value) : m_value(value) {
}
Class(int x, int y) : m_value(x + y) {
}
void change(int value) {
m_value = value;
}
int value() const {
return m_value;
}
private:
int m_value;
};
Here is how Immutable<Class> can be used:
void functionTakingConstReference(const Class& x) {
}
void functionTakingNonConstReference(Class& x) {
}
void functionTakingImmutableClass(Immutable<Class>& x) {
}
void functionTakingValue(Class x) {
}
int main(int argc, char *argv[])
{
// Any constructor of Class can also be used with Immutable<Class>.
Immutable<Class> a;
Immutable<Class> b(1);
Immutable<Class> c(2, 3);
Immutable<Class> d(c);
// Compiles and works as expected.
functionTakingConstReference(a);
functionTakingImmutableClass(a);
functionTakingValue(a);
cout << a.get().value() << endl;
// Doesn't compile because operator= is deleted.
// b = a;
// Doesn't compile because "change" is a non-const method.
// a.get().change(4);
// Doesn't compile because the function takes a non-const reference to Class as an argument.
// functionTakingNonConstReference(a);
return 0;
}
Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
No.
But you can declare all members as const. Then both const and non-const instances would behave largely in the same way and it shouldn't matter whether the instances are const.
I think you are looking for an immutable class. An easy way to get immutability is to declare all member variables as const. This way you ensure that the state of your objects will not change after construction.
This guarantee is independent of whether your object is const and even if you have non-const member functions for that class.
For example:
class Foo
{
public:
Foo(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
private:
const int m_id;
const double m_value;
};
Another way you could generate an immutable object of any type is through a template class. Something like this:
class Bar
{
public:
Bar(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
void SetId(int id) { m_id = id; }
private:
int m_id;
double m_value;
};
template<typename T>
class MyImmutable
{
public:
const T m_obj;
MyImmutable(const T& obj) : m_obj(obj)
{ }
};
int main()
{
cout << "Hello World!" << endl;
Foo a(1,2.0);
Bar x(2,3.0);
MyImmutable<Bar> y(x);
cout << "a.id = " << a.Id() << endl;
cout << "a.value = " << a.Value() << endl;
cout << "y.id = " << y.m_obj.Id() << endl;
cout << "y.value = " << y.m_obj.Value() << endl;
y.m_obj.SetId(2); // calling non-const member throws an error.
return 0;
}
How can I make a class, which is sometimes readonly, and sometimes writable? One option is with getter/setters and a flag which indicates if the object is read-only, but that is a lot of overhead. I also desire this readonly property to work deeply on the object, making sure that all of the objects it contains are also readonly or writeable. Here's some example code of the desired behavior which I tried but failed to achieve using const.
This question is quite generic, so has probably been asked before, but I wasn't able to find a good solution to this exact problem on stackoverflow.
Example code:
https://ideone.com/4cXyNF
class InnerClass {
public:
InnerClass(int j) : j_(j) {}
int j_;
};
class OuterClass {
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c), pointer_(&c) {}
int i_;
InnerClass& reference_;
InnerClass* pointer_;
};
int main() {
InnerClass c(1);
OuterClass readwrite(2, c);
// Desire these 3 operations to work on the writable object
readwrite.i_ = 3;
readwrite.reference_.j_ = 4;
readwrite.pointer_->j_ = 5;
const OuterClass readonly(6, c);
// COMPILER ERROR: error: assignment of member 'OuterClass::i_'
// in read-only object
// readonly.i_ = 7;
// Desire this to be a compiler error, but it isn't
readonly.reference_.j_ = 8;
// Desire this to be a compiler error, but it isn't
readonly.pointer_->j_ = 9;
return 0;
}
If you change your members to functions, you can create const overloads of the methods like this
class InnerClass {
public:
explicit
InnerClass(int j) : j_(j) {}
int& j() { return j_; }
const int& j() const { return j_; }
private:
int j_;
};
class OuterClass {
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c), pointer_(&c) {}
int& i() { return i_; }
const int& i() const { return i_; }
InnerClass const& reference() const { return reference_; };
InnerClass & reference() { return reference_; };
InnerClass const* pointer() const { return pointer_; };
InnerClass * pointer() { return pointer_; };
private:
int i_;
InnerClass& reference_;
InnerClass* pointer_;
};
int main() {
InnerClass c(1);
OuterClass readwrite(2, c);
// Desire these 3 operations to work on the writable object
readwrite.i() = 3;
readwrite.reference().j() = 4;
readwrite.pointer()->j() = 5;
const OuterClass readonly(6, c);
// COMPILER ERROR: error: assignment of member 'OuterClass::i_'
// in read-only object
readonly.i_ = 7;
// Desire this to be a compiler error, and it is
readonly.reference().j() = 8;
// Desire this to be a compiler error, and it is
readonly.pointer()->j() = 9;
return 0;
}
Live on Coliru
You can achieve this by using member functions to return the references / pointers const if the object itself is const.
class InnerClass {
public:
InnerClass(int j) : j_(j) {}
int j_;
};
class OuterClass
{
InnerClass& reference_;
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c) {}
int i_;
InnerClass & in() { return reference_; }
InnerClass const & in() const { return reference_; }
};
Now neither i_ nor in().j_ is writable in case outer is const:
InnerClass i{ 1 };
OuterClass write(2, i);
write.i_ = 3; // works
write.in().j_ = 3; // works
OuterClass const read(2, i);
read.i_ = 3; // error!
read.in().j_ = 3; // error!
This is a similar solution as some else already posted, but uses a slightly different approach:
class InnerClass {
public:
InnerClass(int j) : j_(j) {}
int j_;
};
template<bool readOnly>
class OuterClass{
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c), pointer_(&c) {}
int i_;
typename std::conditional<readOnly,const InnerClass&, InnerClass&>::type reference_;
typename std::conditional<readOnly,const InnerClass* const, InnerClass*>::type pointer_;
};
int main(int argc,char** args){
InnerClass c(1);
OuterClass<true> readonly(12,c);
//readonly.reference_.j_ = 1; //Error "reference_ is read only"
//readonly.pointer_->j_ = 1; //Error "pointer_ is read only"
OuterClass<false> write(12,c);
write.reference_.j_ = 1;
write.pointer_->j_ = 1;
}
I like to make function which get by reference variable from any integer (float , int , double ..) to as custom type . This type should know which type it was constructed from. For example, say I build my custom type
class Variable
{
public:
Variable(int &v)
Variable(float &v)
Variable(double &v)
Variable(short &v)
void setNuwValue(int &v)
void setNuwValue(float &v)
void setNuwValue(double &v)
void setNuwValue(short &v)
var_type_enum getType();
};
Now in my app I have function which takes this Variable type as an argument
void modifyVar(Variable& var)
{
//1.how to know the var type it can return enum of types or string what ever ..
var_type_enum type = var.getType();
var.setNuwValue(3);
}
As you you can see this is only pseudo code without the implementation which I don't know how to implement and I need help.
In short I want to be able to implement global type var as used in for example javascript "var" type
Try with this:
enum VT
{
VT_int,
VT_float,
VT_double,
VT_short
}
class Variable
{
int i;
float f;
double d;
short s;
VT type;
public:
Variable() : i(0), f(0), d(0), s(0) {}
Variable(int &v) { i = v; type = VT_int; }
Variable(float &v) { f = v; type = VT_float; }
Variable(double &v) { d = v; type = VT_double; }
Variable(short &v) { s = v; type = VT_short; }
void setNuwValue(int &v) { i = v; type = VT_int; }
void setNuwValue(float &v) { f = v; type = VT_float; }
void setNuwValue(double &v) { d = v; type = VT_double; }
void setNuwValue(short &v) { s = v; type = VT_short; }
VT getType() const { return type; }
};
Probably you can make use of templates as shown below.
template<typename T> class Variable
{
public:
const char* getType()
{
return typeid(T).name();
}
void setNuwValue( const T& ValueIn )
{
m_Value = ValueIn;
}
private:
T m_Value;
};
template<typename T>
void modifyVar(Variable<T>& var)
{
const char* type = var.getType();
var.setNuwValue(3);
}
Below example call will return "double" when getType() is called.
Variable<double>Var;
modifyVar( Var );
This question already has answers here:
In a templated derived class, why do I need to qualify base class member names with "this->" inside a member function?
(2 answers)
Closed 9 years ago.
I am writing template class for a sudoku puzzle, where the template parameters define the size of the rows and columns. I am using g++-4.8 with C++11 enabled.
I have one compiling issue that I worked around, but I would like to understand why it is not working as expected:
My RowIteratorImpl class derives from VirtualLineIteratorImpl, but I cannot access its fields virtualLineIdx and cellInVirtualLineIdx although this should be possible:
class VirtualLineIteratorImpl : public CellIteratorImpl
{
protected:
size_t virtualLineIdx;
size_t cellInVirtualLineIdx;
public:
VirtualLineIteratorImpl(size_t virtualLineIdx)
: virtualLineIdx(virtualLineIdx), cellInVirtualLineIdx(0)
{}
virtual void increment(size_t offset)
{
virtualLineIdx += offset;
}
};
class RowIteratorImpl : public VirtualLineIteratorImpl
{
public:
using VirtualLineIteratorImpl::VirtualLineIteratorImpl;
virtual size_t getCellIdx() const
{
// TODO: does not compile
// return mivTSudoku::getCellIdxInRow(virtualLineIdx, cellInVirtualLineIdx);
return mivTSudoku::getCellIdxInRow(VirtualLineIteratorImpl::virtualLineIdx, VirtualLineIteratorImpl::cellInVirtualLineIdx);
}
};
The compiler generates the following message:
mivSudoku.h: In member function ‘virtual size_t mivTSudoku::RowIteratorImpl::getCellIdx() const’:
mivSudoku.h:85:39: error: ‘virtualLineIdx’ was not declared in this scope
return mivTSudoku::getCellIdxInRow(virtualLineIdx, cellInVirtualLineIdx);
This is the entire class definition:
#ifndef MIVSUDOKU_H
#define MIVSUDOKU_H
#include <bitset>
#include <iterator>
#include <memory>
template<size_t n, size_t m=n>
class mivTSudoku
{
public:
class Cell
{};
static constexpr size_t getCellIdx(size_t rowIdx, size_t colIdx)
{
return rowIdx * dim + colIdx;
}
static constexpr size_t getCellIdxInRow(size_t rowIdx, size_t cellInRowIdx)
{
return getCellIdx(rowIdx, cellInRowIdx);
}
static constexpr size_t getCellIdxInColumn(size_t columnIdx, size_t cellInColumnIdx)
{
return getCellIdx(cellInColumnIdx, columnIdx);
}
static constexpr size_t getCellIdxInBlock(size_t blockIdx, size_t cellInBlockIdx)
{
return getCellIdx((blockIdx / n) * n + (cellInBlockIdx / m), (blockIdx % n) * m + (cellInBlockIdx % m));
}
class CellIteratorImpl
{
public:
virtual CellIteratorImpl* clone() = 0;
virtual void increment(size_t) = 0;
virtual void getCellIdx() const = 0;
};
class AllCellIteratorImpl : public CellIteratorImpl
{
private:
size_t m_cellIdx;
public:
AllCellIteratorImpl()
: m_cellIdx(0)
{}
virtual void increment(size_t offset)
{
m_cellIdx += offset;
}
virtual void getCellIdx() const
{
return m_cellIdx;
}
};
class VirtualLineIteratorImpl : public CellIteratorImpl
{
protected:
size_t virtualLineIdx;
size_t cellInVirtualLineIdx;
public:
VirtualLineIteratorImpl(size_t virtualLineIdx)
: virtualLineIdx(virtualLineIdx), cellInVirtualLineIdx(0)
{}
virtual void increment(size_t offset)
{
virtualLineIdx += offset;
}
};
class RowIteratorImpl : public VirtualLineIteratorImpl
{
public:
using VirtualLineIteratorImpl::VirtualLineIteratorImpl;
virtual size_t getCellIdx() const
{
// TODO: does not compile
//return mivTSudoku::getCellIdxInRow(virtualLineIdx, cellInVirtualLineIdx);
return mivTSudoku::getCellIdxInRow(VirtualLineIteratorImpl::virtualLineIdx, VirtualLineIteratorImpl::cellInVirtualLineIdx);
}
};
typedef std::bidirectional_iterator_tag CellIterator_tag;
typedef std::iterator<CellIterator_tag, Cell> CellIteratorBase;
class Cellterator : public CellIteratorBase
{
private:
typedef CellIteratorBase baseclass;
protected:
mivTSudoku* pSudoku;
CellIteratorImpl* m_pIterImpl;
public:
Cellterator(mivTSudoku* pSudoku, CellIteratorImpl* impl) noexcept
: pSudoku(pSudoku), m_pIterImpl(impl)
{
}
~Cellterator()
{
delete m_pIterImpl;
m_pIterImpl = nullptr;
}
Cellterator(const Cellterator& rhs) noexcept
: pSudoku(pSudoku), m_pIterImpl(rhs.m_pIterImpl->clone())
{}
Cellterator(Cellterator&& rhs) noexcept
: pSudoku(pSudoku), m_pIterImpl(rhs.m_pIterImpl)
{
rhs.m_pIterImpl = nullptr;
}
Cellterator& operator=(const Cellterator& rhs) noexcept
{
if (this == &rhs) return *this;
this->pSudoku = rhs.pSudoku;
this->m_pIterImpl = rhs.m_pIterImpl->clone();
}
Cellterator& operator=(Cellterator&& rhs) noexcept
{
if (this == &rhs) return *this;
this->pSudoku = rhs.pSudoku;
this->m_pIterImpl = rhs.m_pIterImpl;
rhs.m_pIterImpl = 0;
}
size_t getCellIdx() const
{
return m_pIterImpl->getCellIdx();
}
typedef typename baseclass::reference reference;
reference operator*()
{
return pSudoku->m_field[getCellIdx()];
}
reference const operator*() const
{
return pSudoku->m_field[getCellIdx()];
}
typedef typename baseclass::pointer pointer;
pointer operator->()
{
return pSudoku->m_field + getCellIdx();
}
pointer const operator->() const
{
return pSudoku->m_field + getCellIdx();
}
Cellterator& operator++()
{
m_pIterImpl->increment(1);
return *this;
}
Cellterator operator++(int)
{
Cellterator iter;
this->operator++();
return iter;
}
bool operator==(const Cellterator& rhs) const
{
return getCellIdx()==rhs.getCellIdx();
}
bool operator!=(const Cellterator& rhs) const
{
return !operator==(rhs);
}
};
public:
static const size_t dim = n*m;
static const size_t ncells = dim*dim;
private:
Cell m_field[dim];
};
typedef mivTSudoku<3,3> mivSudoku;
#endif // MIVSUDOKU_H
Can some explain to me why?
The issue is that names not depending on a template argument are looked up only when the template arguments are not known. Since your base class depends on a template argument (implicitly by being nested inside a template) the compiler diesn't look at the base class, yet: until the template is instantiated it could get specialuzed, resulting in a completely different class.
The fix is to make the reference to the base member depend on the template argument, e.g., by using this->virtualLineIdx.