推导 return 类型的成员函数
Deduce return type of member function
在模板函数中,我试图创建一个 std::vector
,其 value_type
依赖于函数模板参数的成员函数。此模板参数仅限于包含具有特定功能的特定类型的唯一指针的向量。例如:
/* somewhere in the code */
std::vector< std::unique_ptr< Widget > > myVec;
/* work with myVec and fill it, then call the relevant function */
func(myVec);
现在函数func
需要检索Widget
的成员函数member_func
的return类型。注意 Widget
也可以是不同的类型,只要它有成员函数 member_func
.
template <typename Vec>
void func(const Vec& vec) {
using ret_type = decltype(Vec::value_type::element_type::member_func()); // Doesn't work
std::vector< ret_type > local_vec;
}
我尝试过各种方法,例如std::result_of
、std::invoke_result
和 decltype
,但我似乎无法让它工作。这甚至可能吗?如果可以,如何实现?
这接近你想要的吗?
#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<>> {});
}
备注
此代码假定 Foo::member_func
的 return_type 不是引用类型。
如果可能的话,我们需要决定是否使用元编程来:
a) 将引用类型转换为 std::reference_wrapper,以便它们可以存储在向量中,或者
b) 使用 std::decay
将引用类型转换为基本类型,这将导致生成副本。
在模板函数中,我试图创建一个 std::vector
,其 value_type
依赖于函数模板参数的成员函数。此模板参数仅限于包含具有特定功能的特定类型的唯一指针的向量。例如:
/* somewhere in the code */
std::vector< std::unique_ptr< Widget > > myVec;
/* work with myVec and fill it, then call the relevant function */
func(myVec);
现在函数func
需要检索Widget
的成员函数member_func
的return类型。注意 Widget
也可以是不同的类型,只要它有成员函数 member_func
.
template <typename Vec>
void func(const Vec& vec) {
using ret_type = decltype(Vec::value_type::element_type::member_func()); // Doesn't work
std::vector< ret_type > local_vec;
}
我尝试过各种方法,例如std::result_of
、std::invoke_result
和 decltype
,但我似乎无法让它工作。这甚至可能吗?如果可以,如何实现?
这接近你想要的吗?
#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<>> {});
}
备注
此代码假定 Foo::member_func
的 return_type 不是引用类型。
如果可能的话,我们需要决定是否使用元编程来:
a) 将引用类型转换为 std::reference_wrapper,以便它们可以存储在向量中,或者
b) 使用 std::decay
将引用类型转换为基本类型,这将导致生成副本。