代码之家  ›  专栏  ›  技术社区  ›  ABu

展开std::reference\u包装的成本

  •  2
  • ABu  · 技术社区  · 7 年前

    鉴于:

    #include <iostream>
    #include <functional>
    
    template<class T> // Just for overloading purposes
    struct behaviour1 : std::reference_wrapper<T const>
    {
        using base_t = std::reference_wrapper<T const>;
        using base_t::base_t;
    
        // This wrapper will never outlive the temporary
        // if used correctly
        behaviour1(T&& t) : base_t(t) {}
    };
    
    template<class T>
    behaviour1(T&&) -> behaviour1<std::decay_t<T> >;
    
    struct os_wrapper : std::reference_wrapper<std::ostream>
    {
        using std::reference_wrapper<std::ostream>::reference_wrapper;
    
        template<class T>
        os_wrapper& operator<<(behaviour1<T> const& v)
        {
            *this << v.get(); // #1
            return *this;
        }
    
        template<class U>
        os_wrapper& operator<<(U&& t)
        { this->get() << t; return *this; }
    };
    
    int main() { os_wrapper(std::cout) << behaviour1(3); }
    

    在第#1行中,在给定特定用例的情况下,是否实际执行了间接寻址(一个以中间方式展开的包装,并且没有复制到除函数参数外的本地引用),或者编译器只是检测到对象以中间方式展开,而只使用原始对象?否则,哪个设计会更好(例如,仅保存对象副本的标量类型的部分专门化是否会更有效)?

    gcc -O3 -std=c++17 )虽然我想两者都有 clang 执行类似的优化技术。

    1 回复  |  直到 7 年前
        1
  •  6
  •   Maxim Egorushkin    7 年前

    使用方法的预期成本 std::reference_wrapper std::reference\u包装 代码可以内联。 The assembly output of statement os_wrapper(std::cout) << behaviour1(3); is :

    movl    $3, %esi
    movl    std::cout, %edi
    call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
    

    内联是Stroustrup喜欢提到的实现零开销抽象的工具。