Это близко к тому, что вы хотели?
#include <vector>
#include <utility>
#include <memory>
struct Foo
{
int member_func();
};
template <typename Vec>
void func(const Vec& vec) {
using ret_type = decltype(std::declval<typename Vec::value_type>()->member_func());
std::vector< ret_type > local_vec;
}
int main()
{
std::vector<std::unique_ptr<Foo>> v;
func(v);
}
Демо: https://godbolt.org/g/dJkSf1
Объяснение:
std::declval<typename Vec::value_type>()
генерирует ссылку на unique_ptr (которыйдолжен использоваться в неоцененном контексте).Затем мы берем decltype для вызова generated_reference->member_function()
.
Это будет тот же тип, что и результат vec[0]->member_func()
Действительно, мы могли бы написать это так:
template <typename Vec>
void func(const Vec& vec) {
using ret_type = decltype(vec.at(0)->member_func());
std::vector< ret_type > local_vec;
}
Который может быть более выразительным и универсальным (Vec
теперь может быть любого типа, который подобен вектору и содержит объекты, похожие на указатели Foo
)
Более того, чем более обобщенно мы приближаемся квычет, тем более общей становится наша func
функция:
#include <vector>
#include <utility>
#include <memory>
#include <set>
#include <iterator>
struct Foo
{
int member_func();
};
template <typename Vec>
void func(const Vec& vec) {
using ret_type = decltype((*std::begin(vec))->member_func());
std::vector< ret_type > local_vec;
}
int main()
{
std::vector<std::unique_ptr<Foo>> v;
func(v);
func(std::array<std::unique_ptr<Foo>, 10> { });
Foo* foos[] = { nullptr, nullptr };
func(foos);
func(std::set<std::shared_ptr<Foo>, std::owner_less<>> {});
}
Примечание
В этом коде предполагается, что return_type для Foo::member_func
не является ссылочным типом.
Если это возможно, нам нужно решить, использовали ли мы метапрограммирование для:
a) преобразования ссылочных типов в std :: reference_wrapper, чтобы они могли быть сохранены в векторе, или
b) преобразовать ссылочные типы в фундаментальные типы, используя std::decay
, что приведет к созданию копий.