对象能知道自己的常量吗?

Tem*_*Rex 10 c++ reflection const-correctness type-traits c++11

使用decltypestd::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??
}
Run Code Online (Sandbox Code Playgroud)

LiveWorkSpace上的输出这有可能吗?

动机:我希望能够检测const成员函数是在const对象上调用还是来自非const对象.该对象可以例如表示高速缓存而该成员可以表示视图.如果缓存是const,则可能使用优化的绘制例程,而如果底层数据是非const,则绘制例程需要定期检查数据是否刷新.

注意:相关的问题询问如何打破const对象的构建,但我不太明白,如果答案对我的问题暗示肯定的NO.如果没有,我想在布尔值中捕获constness以供进一步使用.

编辑:正如@DanielFrey指出的那样,构造函数不是测试constness的好地方.const成员函数怎么样?


UPDATE:感谢大家纠正我最初病态问题,并提供答案的不同部分(建设者的界限不清常量性的rvaluedness this,的环境中的意义const,我忽略了,在-with hindsight-明显超载的把戏,和const参考别名潜伏在阴影中的漏洞).对我来说,这个问题是Stackoverflow处于最佳状态.我决定选择@ JonathanWakely的答案,因为它展示了如何定义MutableImmutable强化constness概念的类,以便以万无一失的方式实现我想要的东西.

Dan*_*rey 6

构造函数(原始问题)不可能因为

12.1构造函数[class.ctor]

4构造函数不得为virtual(10.3)或static(9.4).构造函数可以被调用用于const,volatileconst volatile对象.构造函数不得申报const,volatileconst volatile(9.3.2).constvolatile语义(7.1.6.1)不适用于正在构建的对象.它们在最派生对象(1.8)的构造函数结束时生效.不应使用ref-qualifier声明构造函数.

对于成员函数(当前问题),您可以简单地提供a const和非const重载,将两者都转发到将constness作为布尔模板参数的(私有)方法.


Jon*_*ely 5

正如其他人所说,你无法判断对象是否const在成员函数中声明.您只能判断它是否在const上下文中被调用,这是不一样的.

动机:我希望能够检测const成员函数是在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
Run Code Online (Sandbox Code Playgroud)

您可以通过定义单独的可变和不可变类型在类型系统中对其进行建模.

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!
};
Run Code Online (Sandbox Code Playgroud)

现在,如果创建一个缓存,ImmutableCache你知道它不能改变,那么它将取代你之前对"const"对象的想法.A MutableCache可以更改,因此需要检查刷新的数据.