Рассмотрим следующую проблему: у меня есть несколько классов, каждый из которых реализует функцию get()
. Следующие container1
и container2
являются примерами таких классов:
struct expensive_type {
int v;
};
struct container1 {
expensive_type get() const {
return { 1 };
}
};
struct container2 {
expensive_type x;
expensive_type& get() {
return x;
}
};
Я хочу создать оболочку, настроенную на C
и F
, которая реализует ту же функциональность get()
дляC
, но применяет функцию к результату:
template<typename C, typename F>
struct wrapper {
F f;
C c;
decltype(auto) get() {
return f(c.get());
}
};
Теперь я хотел бы создать функцию f
для тривиальной оболочки, которая просто возвращает свой аргумент без изменений. Я думал, что это будет работать:
auto f = [](auto&& x) -> decltype(auto) {
return forward<decltype(x)>(x);
};
wrapper<container1, decltype(f)> trivial_wrapper1 { f, {} };
wrapper<container2, decltype(f)> trivial_wrapper2 { f, {} };
, но, к сожалению, trivial_wrapper1.get()
возвращает expensive_type{0}
вместо expensive_type{1}
(по крайней мере, с флагом -O2
). Я думаю, что проблема связана с висячими ссылками, но я не могу понять, как это исправить.
Мой вопрос: как правильно реализовать функцию f
, чтобы она действовала как идеальная личность, не копируя аргумент?
Для пояснения, вот примеры предполагаемого поведения:
cout << trivial_wrapper1.get().v << endl; // should print 1, prints 0 as of now
trivial_wrapper2.get().v = 2;
cout << trivial_wrapper2.c.x.v << endl; // should print 2, and it does as of now