问题
Given:
#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); }
In line #1, is the indirection actually performed, given that specific use case (a wrapper that is inmediatly unwrapped, and nor copied neither bound to local references except function parameters), or will the compiler just detect that the object is inmediatly unwrapped and just use the original object instead? Which will be a better design otherwise (for example, whether a partial specialization for scalar types that just save a copy of the object will be more efficient)?
I'm interested specifically in gcc
(version 7, -O3 -std=c++17
) although I guess both clang
and gcc
performs similar optimization techniques.
回答1:
The expected cost of using methods of std::reference_wrapper
in an optimized build is 0 because all std::reference_wrapper
code can be inlined. 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)
Inlining is what enables zero-overhead abstractions which Stroustrup likes to mention.
来源:https://stackoverflow.com/questions/46957595/cost-of-unwrapping-a-stdreference-wrapper