据我了解,在类型名称之后,单个 &
表示左值引用,双 &&
表示右值引用或“推导引用”,也称为universal reference作者:斯科特·迈耶斯。但我从未在函数或方法签名中见过三重 &&&
。它代表什么?
以下代码生成一个具有三重 &&&
的方法:
#include <iostream>
#include <utility>
template<typename ostream> void foo(ostream&& out) {
out << "foo" << std::endl;
}
template<typename ostream> void bar(ostream&& out) {
foo(std::forward<ostream>(out));
}
int main() {
bar(std::cout);
}
使用g++-4.8.1
编译代码后,我运行nm -j a.out | c++filt
。 -j
开关(我相信)是非标准的,它意味着只显示符号名称(没有值或类型)。我明白了:
__GLOBAL__sub_I_triple_ampersand.cpp
void bar<std::ostream&>(std::ostream&&&)
void foo<std::ostream&>(std::ostream&&&)
__static_initialization_and_destruction_0(int, int)
std::ostream::operator<<(std::ostream& (*)(std::ostream&))
std::ios_base::Init::Init()
std::ios_base::Init::~Init()
std::cout
std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
std::ostream&&& std::forward<std::ostream&>(std::remove_reference<std::ostream&>::type&)
std::piecewise_construct
std::__ioinit
std::basic_ostream<char, std::char_traits<char> >& std::operator<<<std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
___cxa_atexit
__mh_execute_header
_main
dyld_stub_binder
当我使用clang++
编译时,我得到类似的输出。所以我的问题是,三个与号代表什么?显然我无法直接在代码中编写 &&&
。是因为我的 c++filt
错误地整理了符号吗?我在 Mac OS X 10.8 上使用系统提供的 c++filt
。
最佳答案
将模板参数命名为
ostream
并使用std::ostream&
实例化这一事实令人困惑。在分解过程中存在一个小错误(它应该放置一个空格来打破
&
组,因为它的含义是& &&
而不是&& &
),但是连续&
本身的存在不是问题:破坏名称的另一种方法是void bar<$T=std::ostream$&>($T$&&)
,即破坏的名称包含对参数的反向引用,而不是类型本身的扩展。为什么?一般来说,实例化的损坏名称必须表示精确的实例化模板及其参数(而不是使用由折叠规则或扩展对特征的引用等产生的签名)作为同名的两个不同函数模板的实例化相同签名中的签名可以在程序中有效地共存(我不认为它们可以在编译单元中共存,但名称查找和重载解析在 C++ 中非常复杂,我可能会弄错),并且使用简化的签名将无法充分合并它们。以特征为例,我目前无法想到具有引用折叠规则(*)的一个,后面的两个函数模板可能在程序中重载(即使在同一个 CU 中)
template <typename T> struct Traits{}; template <typename T> void f(typename Traits<T>::T1) { return; } template <typename T> void f(typename Traits<T>::T2) { return; }
但是如果你有以下特质专精
template <> struct Traits<int> { typedef int T1; typedef int T2; };
您不能在两者都可见的地方使用
f<int>(42)
,因为存在歧义,但通过使它们有选择地可见,您可以在一个 CU 中使用一个,在另一个 CU 中使用另一个,因此重整必须能够有所作为。
(*) 可能没有,我不记得曾见过提到的,一旦该机制必须就位(另一个原因是限制损坏名称的大小),它会更安全且更安全也可能更容易继续使用它来完成所有事情。
关于c++ - 三重与号 `&&&` 在 C++ 中代表什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19510825/