стоимость распаковки std :: reference_wrapper

Дано:

#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 (версия 7, -O3 -std=c++17) хотя думаю оба clang а также gcc выполняет аналогичные методы оптимизации.

1

Решение

Ожидаемая стоимость использования методов std::reference_wrapper в оптимизированной сборке 0, потому что все std::reference_wrapper код может быть встроен. Сборка вывода постановки os_wrapper(std::cout) << behaviour1(3); является:

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

Встраивание — это то, что позволяет использовать абстракции без накладных расходов, которые любит упоминать Страуструп.

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]