推导成员函数的返回类型

问题描述 投票:0回答:2

在模板函数中,我试图创建一个

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
需要检索
member_func
的成员函数
Widget
的返回类型。请注意,
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
,但我似乎无法让它发挥作用。这是否可能?如果可以,如何实现?

c++ templates decltype result-of
2个回答
4
投票

这接近你想要的吗?

#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 的引用(必须在未评估的上下文中使用)。然后我们采用调用
generated_reference->member_function()
的 decltype。

这与

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
将引用类型转换为基本类型,这将导致创建副本。


0
投票

这是我想出的方法,它似乎适用于大多数情况。

template <typename TYPE, typename FUNCPTR, typename...ARGS>
using mfunc_return_t = decltype((std::declval<TYPE>().*std::declval<FUNCPTR>())(std::declval<ARGS&>()...));

然后我在调用提供的成员函数的函数中使用它。

template <typename FUNCPTR, typename TYPE, typename...ARGS>
mfunc_return_t<TYPE, FUNCPTR, ARGS...> SafeCall(TYPE* ptr, FUNCPTR func, ARGS&...args)
{
    if (ptr != nullptr)
        return (ptr->*func)(args...);
    using ReturnType = mfunc_return_t<TYPE, FUNCPTR, ARGS...>;
    return DefaultValue<ReturnType>();
}

我有几个用于处理类型的 DefaultValue 实现,包括算术类型、指针、void 和其他默认可构造类型。

然后我可以做类似的事情

auto returnVal = SafeCall(pointer, &MyClass::FunctionName, arg1, arg2);

return SafeCall(pointer, &MyClass::FunctionName, arg1, arg2);
© www.soinside.com 2019 - 2024. All rights reserved.