[namespace.std] 引用 std
名称空间中的大多数功能。这是一个很大的陷阱,因为尽管这可能会停止在其他编译器上工作或更糟糕的是,但似乎通常可以通过标准图书馆函数作为参数。
据推测,这是为了允许实施方式特别优化标准库。该限制使C ++更难使用。
您能否给出明确的示例,说明如何从 std
名称空间中受益于这种限制?
如果这些优化非常重要以至于使C ++更难使用,为什么一些非系统库不需要同样的事情呢?
[namespace.std] disallows taking the address of, or a reference to, most functions in the std
namespace. This is a big pitfall, as it often seems to work to pass a standard-library function as an argument, even though this could stop working, or worse, on a different compiler.
Presumably, this was done to allow implementations to optimize the standard library specially. This restriction makes C++ harder to use.
Can you give explicit examples of how C++ implementations benefit from this restriction on the std
namespace?
If these optimizations are so important as to warrant making C++ harder to use, why don't some non-system libraries need the same thing?
发布评论
评论(1)
首先,值得注意的是,这种设计并非源于C。它在C ++中是全新的。
- C89标准,4.1.6使用库函数
由于多种原因,这些严格的保证在C ++中会非常限制。
作为免责声明,我无法找到比贾恩本人的名言,所以我要说的一切都是社区共识和个人经验的集合。
1。添加过载可能会破坏源兼容性
说明您有一个函数:
最初可以安全地调用
std :: partition(begin,end,end,is_even)
,但是如果long
long <<
> /code>和除了
,然后使用int
之外,还添加了长长的长is_even
的使用将变得不明显。本质上,任何可寻址功能将来都无法收到额外的超载,因为它会破坏现有代码。这就是为什么 [namespace.std] - 形成”。
2。签名更容易更改,而在C中的
另一种破坏兼容性是使现有功能更通用。
例如,它使标准库使其函数更加通用,例如“转动:
进入
”并随后
使用功能过载和模板等功能,函数的实现可以随着时间的推移而发生巨大变化。
当然,没有人可以预见到数学库中的这些急剧变化,但是对不可原值的功能的限制使它们成为可能,而不会破坏任何合格的代码。
3。函数可能没有地址,
有两个可能的原因导致函数可能没有任何地址:
consteval
,C ++ 20)决定该决定的重要贡献者。
如今,通常会在标准库中使用的任何内在物质围绕 inline 函数包装器,但这会变成常见的做法,这在一天中并不明显。
内在标准库功能的一个更现代的示例是。
std :: Move
,它在MSVC STL中被“有点内在”。请参阅改善C ++
4。“函数”可能是C ++中的函数对象
,也可以作为函数对象实现函数,例如:
如果函数实际上是函数对象,那么在采用其地址时,行为会有所不同因为您不会得到功能指针。但是,称其为行为相同(除了ADL没有发生)。
这是通过使函数不可遮盖而成为可能的另一种灵活性形式。
结论
使得掌握标准库功能的地址将大大降低实施者的灵活性。
几乎所有更改(例如增加过载)都会打破兼容性,从而有效地冻结语言进度。
在C中,这并不是一个大问题,无论如何,功能签名还是会冻结的,但在C ++中会产生重大的负面后果。
Firstly, it's worth noting that this design did not originate in C; it's entirely new in C++.
- C89 Standard, 4.1.6 Use of library functions
These strict guarantees would be very restrictive in C++ though, for a number of reasons.
As a disclaimer, I haven't been able to find quotes from Bjarne himself, so everything that I'm about to say is a collection of community consensus and personal experience.
1. Adding overloads may break source compatiblity
Say you have a function:
It may be initially safe to call
std::partition(begin, end, is_even)
, but if an overload forlong
andlong long
was added in addition toint
, then the use ofis_even
would become ill-formed.Essentially, any addressable function cannot receive extra overloads in the future because it breaks existing code. This is why [namespace.std] specifically says "possibly ill-formed".
2. Signatures are more prone to change than in C
Another way to break compatibility is to make an existing function more generic.
For example, it lets the standard library make its functions more generic, such as turning:
into
and subsequently into
With features such as function overloading and templates, the implementation of a function can change drastically over time.
Of course, no one could have foreseen these drastic changes in the math library, but the restrictions on non-addressable functions have made them possible without breaking any conforming code.
3. Functions may not have an address
There are two possible reasons why a function might not have any address:
consteval
, C++20)The former reason may have been a significant contributor to the decision.
Nowadays, there is usually an
inline
function wrapper around any intrinsics used in the standard library, but this would turn into common practice was not obvious back in the day.A more modern example of intrinsic standard library functions is
std::move
, which was made "kinda intrinsic" in the MSVC STL.See Improving the State of Debug Performance in C++.
4. "Functions" may be function objects
In C++, it is also possible to implement a function as a function object, such as:
If a function is actually a function object, then there would be a difference in behavior when taking its address, as you wouldn't get a function pointer. However, calling it would behave the same (except ADL doesn't take place).
This is yet another form of flexibility that is made possible by making functions non-addressable.
Conclusion
Making it possible to take the address of standard library functions would have significantly reduced the flexibility of implementers.
Almost any change, such as adding overloads would break compatibility, effectively freezing language progress.
This is not a big issue in C, where function signatures are frozen anyway, but would have significant negative consequences in C++.