1

我知道在类型名之后,单&表示左值引用,双&&表示右值引用或“推导引用”,斯科特迈耶斯也将其称为通用引用。但我从未&&&在函数或方法签名中看到过三元组。它代表什么?

下面的代码产生一个带有三元组的方法&&&

#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的符号分解不正确吗?我正在使用c++filtMac OS X 10.8 上提供的系统。

4

1 回答 1

3
  • 您命名模板参数ostream并实例化它的事实std::ostream&令人困惑。

  • 拆解中有一个小错误(它应该放置一个空格来破坏组的&含义 is& &&和 not && &),但是连续&本身的存在不是问题:另一种拆解名称的方法是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 中使用另一个,因此修改必须能够有所作为。

(*) 有可能没有,我不记得见过提到过,一旦机制必须到位(另一个原因是限制损坏名称的大小),它更安全,也可能更容易继续将它用于一切。

于 2013-10-22T08:05:54.797 回答