С 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 для достижения того, что я хочу, безошибочным способом.
Как уже говорили другие, вы не можете сказать, был ли объект объявлен как 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
может измениться, поэтому необходимо проверить обновленные данные.
Это не возможно для конструкторов (оригинальный вопрос) из-за
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, перенаправьте оба в (приватный) метод, который принимает константу как логический параметр шаблона.
Тип 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
}
Остерегайтесь ограничений, изложенных во фрагменте, хотя.
что будет работать ??
Ничего не получится.
Объект, выполняющий его конструктор никогда 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
контекст.
Не знаю возможно ли таким образом, посредством значения члена, установленного в конструкторе, но объект может сообщить о своем постоянстве с помощью функций-членов:
struct Test
{
bool is_const() const
{
return(true);
}
bool is_const()
{
return(false);
}
};
Это невозможно, поскольку возможно, что конкретное значение будет одновременно рассматриваться как const
и не const
, Рассматривать
MyType t = ...;
MyType& nonConstRef = t;
const MyType& constRef = t;
С этой точки зрения t
имеет как const
и неконстантная ссылка.
Обнаружение константности внутри объекта невозможно, но вы заявляете, что ваша мотивация …
«Я хочу быть в состоянии определить, вызывается ли функция-член 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! правда