Может ли объект знать свою собственную константность?

С decltype а также std::is_const константность переменной может быть обнаружена извне. Но возможно ли, чтобы объект знал свою собственную постоянство? Использование должно быть как:

#include <type_traits>
#include <iostream>
#include <ios>

struct Test
{
Test() {}

bool print() const
{
// does not work as is explained in https://stackoverflow.com/q/9890218/819272
return std::is_const<decltype(*this)>::value; // <--- what will work??
}
};

int main()
{
Test t;
const Test s;

// external constness test
std::cout << std::boolalpha << std::is_const<decltype(t)>::value << "\n";
std::cout << std::boolalpha << std::is_const<decltype(s)>::value << "\n";

// internal constness test
std::cout << std::boolalpha << t.print() << "\n";
std::cout << std::boolalpha << s.print() << "\n"; // <--- false??
}

Выход на LiveWorkSpace Это как-то возможно?

МОТИВАЦИЯ: Я хочу иметь возможность определить, вызывается ли функция-член const для объекта const или происходит от неконстантного объекта. Объект может, например, представлять кеш и член представление. Если бы кэш был константным, то, вероятно, можно было бы использовать оптимизированную процедуру отрисовки, тогда как, если лежащие в основе данные были неконстантными, процедура отрисовки должна была бы периодически проверять, обновлялись ли данные.

НОТА: связанный вопрос спрашивает, как сломать сборку для const объектов, но я не совсем понимаю, подразумевает ли ответ на это определенное НЕТ для моего вопроса. Если нет, я хочу записать константу в логическое значение для дальнейшего использования.

РЕДАКТИРОВАТЬ: как было отмечено @DanielFrey, конструктор не является хорошим местом для проверки на константность. Как насчет функции-члена const?


ОБНОВИТЬСпасибо всем за то, что исправили мой изначально некорректный вопрос и предоставили различные части ответа (плохо определенная конструктивность, ценность thisконтекстное значение const, — задним числом — очевидный трюк с перегрузкой, который я упустил из виду, и константная контрольная лазейка, скрывающаяся в тени). Для меня этот вопрос был Stackoverflow в лучшем виде. Я решил выбрать ответ @ JonathanWakely, потому что он показал, как определить Mutable а также Immutable классы, которые укрепляют концепцию constness для достижения того, что я хочу, безошибочным способом.

10

Решение

Как уже говорили другие, вы не можете сказать, был ли объект объявлен как const изнутри функции-члена. Вы можете только сказать, если он вызывается в const контекст, который не совпадает.

МОТИВАЦИЯ: Я хочу быть в состоянии определить, вызывается ли функция-член const для объекта const или исходит от неконстантного объекта. Объект может, например, представлять кеш и член представление. Если бы кэш был константным, то, вероятно, можно было бы использовать оптимизированную процедуру отрисовки, тогда как, если лежащие в основе данные были неконстантными, процедура отрисовки должна была бы периодически проверять, обновлялись ли данные.

Вы не можете сказать это достоверно.

struct A
{
void draw() { fut = std::async(&A::do_draw, this, false); }
void draw() const { fut = std::async(&A::do_draw, this, true); }
void update(Data&);
private:
void do_draw(bool this_is_const) const;
mutable std::future<void> fut;
};

A a;
const A& ca = a;
ca.draw();           // object will think it's const, but isn't
Data new_data = ...;
a.update(new_data);  // do_draw() should recheck data, but won't

Вы можете моделировать его в системе типов, определяя отдельные изменяемые и неизменяемые типы.

struct Base
{
virtual ~Base();
virtual void draw() const = 0;
protected:
void do_draw(bool) const;
};

struct MutableCache : Base
{
virtual void draw() const { fut = std::async(&Base::do_draw, this, false); }
void update();
};

struct ImmutableCache : Base
{
virtual void draw() const { fut = std::async(&Base::do_draw, this, true); }
// no update function defined, data cannot change!
};

Теперь, если кеш создается как ImmutableCache ты это знаешь не может изменить, так что заменяет вашу предыдущую идею «const» объекта. MutableCache может измениться, поэтому необходимо проверить обновленные данные.

5

Другие решения

Это не возможно для конструкторов (оригинальный вопрос) из-за

12.1 Конструкторы [class.ctor]

4 Конструктор не должен быть virtual (10.3) или static (9.4). Конструктор может быть вызван для const, volatile или же const volatile объект. Конструктор не должен быть объявлен const, volatile, или же const volatile (9.3.2). const а также volatile семантика (7.1.6.1) не применяется к строящемуся объекту. Они вступают в силу, когда заканчивается конструктор для самого производного объекта (1.8). Конструктор не должен быть объявлен с квалификатором ref.

Для функций-членов (текущий вопрос) вы можете просто предоставить const и неconst overload, перенаправьте оба в (приватный) метод, который принимает константу как логический параметр шаблона.

6

Тип this (и, следовательно, *this) определяется cv-квалификатором функции и не изменяется в зависимости от того, является ли фактический объект cv-квалифицированным или нет.

§9.3.2 [class.this] p1

В теле нестатической (9.3) функции-члена ключевое слово this является выражением prvalue, значением которого является адрес объекта, для которого вызывается функция. Тип this в функции-члене класса X является X*, Если функция-член объявлена const, тип this является const X*, если функция-член объявлена volatile, тип this является volatile X*и если функция-член объявлена const volatile, тип this является const volatile X*,

Итак, вы не можете видеть внутри функции-члена, является ли объект, на который он вызывается, const, но вы можете заставить компилятор вызывать разные функции в зависимости от constНесс:

struct X{
void f(){ /* non-const object */ }
void f() const{ /* const object */ }
};

int main(){
X x1;
X const x2;
x1.f(); // calls non-const 'f'
x2.f(); // calls const 'f'

// but beware:
X const& rx = x1;
rx.f(); // calls const 'f', because the "object" it's invoked on is const
}

Остерегайтесь ограничений, изложенных во фрагменте, хотя.

3

что будет работать ??

Ничего не получится.

Объект, выполняющий его конструктор никогда const. Он может быть назначен только const переменная после конструктор прошел свой курс.

Он также не может быть определен для функций-членов (включая неконстантные функции-члены, так как const_cast возможно, был использован)

Константность — это свойство, которое существует в каждый звонок на сайте, не как свойство самого тела функции.

МОТИВАЦИЯ: я хочу быть в состоянии определить, вызывается ли функция-член const для объекта const

Вы не можете сделать это, но вы можете подойти ближе …

class C
{
public:
void func() const
{
std::cout << "const!";
func_impl();
}
void func()
{
std::cout << "non-const!";
func_impl();
}
private:
void func_impl() const;
};

Объект может, например, представлять кеш и член представление. Если бы кэш был константным, то, вероятно, можно было бы использовать оптимизированную процедуру отрисовки, тогда как, если лежащие в основе данные были неконстантными, процедура отрисовки должна была бы периодически проверять, обновлялись ли данные.

Это было бы ненадежным использованием const так как const не является собственностью самого объекта. Это свойство текущего контекста, который используется объектом.

Обнаружив, что это const в текущем контексте не говорит вам, что объект всегда обрабатывался в const контекст.

3

Не знаю возможно ли таким образом, посредством значения члена, установленного в конструкторе, но объект может сообщить о своем постоянстве с помощью функций-членов:

struct Test
{
bool is_const() const
{
return(true);
}

bool is_const()
{
return(false);
}
};
3

Это невозможно, поскольку возможно, что конкретное значение будет одновременно рассматриваться как const и не const, Рассматривать

MyType t = ...;
MyType& nonConstRef = t;
const MyType& constRef = t;

С этой точки зрения t имеет как const и неконстантная ссылка.

2

Обнаружение константности внутри объекта невозможно, но вы заявляете, что ваша мотивация …

«Я хочу быть в состоянии определить, вызывается ли функция-член const для объекта const или исходит от неконстантного объекта».

Ну, это легко, просто предоставьтеconst перегрузки.

Перегрузки могут быть перенесены на общую реализацию, например, следующее:

#include <type_traits>
#include <iostream>
using namespace std;

class Test
{
private:
template< class CvTest >
static void print( CvTest& o )
{
cout << boolalpha;
cout << "> object says: Hey, const = " << std::is_const<CvTest>::value << "!" << endl;
}

public:
bool print()        { return (print( *this ), false); }
bool print() const  { return (print( *this ), true); }
};

int main()
{
Test t;
const Test s;

cout << "External constness test:" << endl;
cout << boolalpha << is_const<decltype(t)>::value << "\n";
cout << boolalpha << is_const<decltype(s)>::value << "\n";

cout << endl;

cout << "Internal constness test:" << endl;
cout << boolalpha << t.print() << "\n";
cout << boolalpha << s.print() << "\n";
}

Результаты:

Внешний тест на константность:
ложный
правда

Тест внутренней константности:
> Объект говорит: эй, const = false!
ложный
> Объект говорит: эй, const = true!
правда
2