为什么指针类型没有 std::as_const 重载
Why no std::as_const overload for pointer types
我刚遇到 std::as_const
,我对以下代码段中最后一行的输出感到惊讶:
#include <cstdio>
#include <utility>
struct S {
void foo() { std::puts("foo: non const"); }
void foo() const { std::puts("foo: const"); }
};
int main() {
S s;
s.foo(); // foo: non const
std::as_const(s).foo(); // foo: const
auto* s_ptr = &s;
s_ptr->foo(); // foo: non const
std::as_const(s_ptr)->foo(); // foo: non const (?)
}
查看文档,我明白了为什么调用 foo
的非 const
重载:
std::as_const(s_ptr)
returns a S* const&
,即对常量的引用
指向非常量 S
的指针,而不是 S const*
,即指向常量 S
的指针,就像我希望的那样
有所期待。
所以,我的问题是为什么标准不也为指针类型提供 std::as_const
重载?例如。类似于:
template <class T>
constexpr std::add_const_t<T>* as_const(T* t) noexcept {
return t;
}
编辑: 论文 P0007R1 std::as_const
的动机之一是选择函数重载而不必求助于 const_cast
. P0007R1 提供了这个例子:
int processEmployees( std::vector< Employee > &employeeList );
bool processEmployees( const std::vector< Employee > &employeeList );
A larger project often needs to call functions, like processEmployees
, and
selecting among specific const
or non-const
overloads. [...]
这就是为什么我有点惊讶它在以下情况下对重载解决没有帮助
应用于我发布的代码中的指针,也不应用于:
std::as_const(this)->foo();
也不选择以下重载中的后者:
int processEmployees( std::vector< Employee > *employeeList );
bool processEmployees( const std::vector< Employee > *employeeList );
std::as_const
的目的是能够将非 const
左值引用为 const
左值,以便它在它所在的上下文中不可修改用过的。换句话说 std::as_const(x)
应该是一个 shorthand 用于写
const auto& y = x;
然后使用 y
.
它已经做得很好了,所以不需要指针的特殊行为。
这是一个简单的例子,其中建议的额外过载会产生严重的负面影响:
std::vector<int> vec = /*...*/;
for(auto it = std::begin(vec); it != std::end(vec); it++)
func(std::as_const(it));
这里的目的是确保函数 func
不能修改 it
,因为迭代向量的责任在于 for
循环。如果 func
只是采用迭代器 by-value 或 const
引用,那么 std::as_const
不是严格要求的,但无论如何作为安全措施还是有意义的,因为有多个重载func
,其中一些确实修改了他们的论点。
auto
这是一些迭代器类型。它可能是一个指针。或者它可以是 class 类型。根据您建议的 as_const
重载,这会中断,具体取决于 std::vector
迭代器的实现方式。
std::as_const(it)
应该说 it
不应通过这种使用进行修改。它不应该说明对象 it
引用是否可修改。这不是它的目的。当然,添加一个使 referenced 对象 non-modifiable 的函数是有意义的。但是它应该有一个不同的名字,你可能想要为任意迭代器实现它,而不是专门为指针。基本上,一个 iterator-to-const
-迭代器适配器。
我刚遇到 std::as_const
,我对以下代码段中最后一行的输出感到惊讶:
#include <cstdio>
#include <utility>
struct S {
void foo() { std::puts("foo: non const"); }
void foo() const { std::puts("foo: const"); }
};
int main() {
S s;
s.foo(); // foo: non const
std::as_const(s).foo(); // foo: const
auto* s_ptr = &s;
s_ptr->foo(); // foo: non const
std::as_const(s_ptr)->foo(); // foo: non const (?)
}
查看文档,我明白了为什么调用 foo
的非 const
重载:
std::as_const(s_ptr)
returns a S* const&
,即对常量的引用
指向非常量 S
的指针,而不是 S const*
,即指向常量 S
的指针,就像我希望的那样
有所期待。
所以,我的问题是为什么标准不也为指针类型提供 std::as_const
重载?例如。类似于:
template <class T>
constexpr std::add_const_t<T>* as_const(T* t) noexcept {
return t;
}
编辑: 论文 P0007R1 std::as_const
的动机之一是选择函数重载而不必求助于 const_cast
. P0007R1 提供了这个例子:
int processEmployees( std::vector< Employee > &employeeList );
bool processEmployees( const std::vector< Employee > &employeeList );
A larger project often needs to call functions, like
processEmployees
, and selecting among specificconst
or non-const
overloads. [...]
这就是为什么我有点惊讶它在以下情况下对重载解决没有帮助 应用于我发布的代码中的指针,也不应用于:
std::as_const(this)->foo();
也不选择以下重载中的后者:
int processEmployees( std::vector< Employee > *employeeList );
bool processEmployees( const std::vector< Employee > *employeeList );
std::as_const
的目的是能够将非 const
左值引用为 const
左值,以便它在它所在的上下文中不可修改用过的。换句话说 std::as_const(x)
应该是一个 shorthand 用于写
const auto& y = x;
然后使用 y
.
它已经做得很好了,所以不需要指针的特殊行为。
这是一个简单的例子,其中建议的额外过载会产生严重的负面影响:
std::vector<int> vec = /*...*/;
for(auto it = std::begin(vec); it != std::end(vec); it++)
func(std::as_const(it));
这里的目的是确保函数 func
不能修改 it
,因为迭代向量的责任在于 for
循环。如果 func
只是采用迭代器 by-value 或 const
引用,那么 std::as_const
不是严格要求的,但无论如何作为安全措施还是有意义的,因为有多个重载func
,其中一些确实修改了他们的论点。
auto
这是一些迭代器类型。它可能是一个指针。或者它可以是 class 类型。根据您建议的 as_const
重载,这会中断,具体取决于 std::vector
迭代器的实现方式。
std::as_const(it)
应该说 it
不应通过这种使用进行修改。它不应该说明对象 it
引用是否可修改。这不是它的目的。当然,添加一个使 referenced 对象 non-modifiable 的函数是有意义的。但是它应该有一个不同的名字,你可能想要为任意迭代器实现它,而不是专门为指针。基本上,一个 iterator-to-const
-迭代器适配器。