我对下面的代码感到困惑,其中类baz
通过代理类bar
授予对其内部数据的访问权限:
struct Foo{};
template<class T>
struct Bar
{
Bar(T &val_): val(val_) {}
T &val;
};
struct Baz
{
Bar<const Foo> get() const {return Bar<const Foo>(foo);}
Bar<Foo> get() {return Bar<Foo> (foo);}
Foo foo;
};
struct FooBaz
{
FooBaz(Baz &baz_): baz(baz_) {}
// Bar<const Foo> get() const {return baz.get();} // this do not compile
Bar<const Foo> get() const {return const_cast<const Baz &>(baz).get();} // the const_cast seems to be required
Baz &baz;
};
似乎我必须执行一个const_cast
来分派到正确的baz::get()
函数。
我不明白的第一件事是,如果foobaz::baz
是一个普通的baz
而不是一个引用,那么它可以工作:
struct Foo{};
template<class T>
struct Bar
{
Bar(T &val_): val(val_) {}
T &val;
};
struct Baz
{
Bar<const Foo> get() const {return Bar<const Foo>(foo);}
Bar<Foo> get() {return Bar<Foo> (foo);}
Foo foo;
};
struct FooBaz
{
FooBaz(Baz &baz_): baz(baz_) {}
Bar<const Foo> get() const {return baz.get();} // Ok
Baz baz;
};
我对const函数成员的理解是,它使这个
成为const的指针,但实际上我并不完全清楚它的含义。。。 所有的数据成员都是‘就像它们是常量’吗? 对此有明确的提法吗?
另一件有趣的事情是,如果我使用std::reference_wrapper
作为代理类,那么它在没有const_cast
:
#include <functional>
struct Foo {};
struct Baz
{
std::reference_wrapper<const Foo> get() const {return std::cref(foo);}
std::reference_wrapper<Foo> get() {return std::ref (foo);}
Foo foo;
};
struct FooBaz
{
FooBaz(Baz &baz_): baz(baz_) {}
std::reference_wrapper<const Foo> get() const {return baz.get();} // Ok
Baz &baz;
};
std::reference_wrapper
有什么神奇之处?
谢啦!
如果foobaz::baz
是普通的baz
而不是引用,则可以工作:
这才是重点。 在const
成员函数中,数据成员也被视为const
。 请注意,对于引用,这意味着引用成员本身,而不是被引用的对象。 即baz
将变成baz&; 常量baz;
(常量引用),而不是baz常量& baz;
(引用常量)。 事实上,引用不能进行常量限定,常量限定符只是被忽略,因为即使在const
成员函数中,baz.get();
也始终调用非常量的get()
。
对于std::reference_wrapper
版本,它没有改变,baz.get();
仍然调用非常量get()
并返回std::reference_wrapper
。 std::reference_wrapper
具有转换构造函数,因此,转换后的std::reference_wrapper
存储对从std::reference_wrapper
获得的对象的引用(通过转换运算符)。
我必须执行一个const_cast
来分派到正确的baz::get()
函数。
是的。 或std::as_const
,或使Bar<;t>
可转换为Bar<;constT>
。
我对const函数成员的理解是,它使this指针指向const,但实际上我并不完全清楚它的含义。。。 所有的数据成员都是‘就像它们是常量’吗?
是的,成员的行为就像是常量
。
表达式e1->e2
完全等同于内置类型的(*e1).e2
; 这就是为什么下面的规则只处理E1.E2
。
在表达式E1.E2
中:
如果E2
是非静态数据成员:
如果E2
是引用类型T&;
或T&;
,则结果是T
类型的L值,指定E2引用的对象或函数,否则,如果E1
是L值,则结果是指定E1
的非静态数据成员的L值,否则(如果E1
是xvalue(可从prvalue物化)),则结果是指定E1
的非静态数据成员的xvalue。
如果e2
不是可变成员,则结果的CV限定条件是e1
和e2
的CV限定条件的并集,否则(如果e2
是可变成员),则结果的CV限定条件是e1
和e2
的Volatile限定条件的并集;
-cp首选项
当通过指向const
类的指针访问时,其成员变为const
。
但恒常性只在顶层添加。 如果通过指向const
的指针访问int*const member;
,则它将成为int*const member;
,而不是const int*const member;
。
引用以类似的方式工作,但是因为引用本身不能是const
1,所以它们的类型不会改变。
如果我使用std::reference_wrapper
作为代理类,那么它在没有const_cast
的情况下工作
这是因为它有一个构造函数,允许从std::reference_wrapper
构造std::reference_wrapper
。
1是的,引用在创建后不能更改为指向其他对象,但形式上它不是常量
。 std::is_const
返回引用的false
。