如何获取没有对象的成员函数的返回类型?

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

我有许多无法修改的类。每个构造函数都有一个复制构造函数、至少一个其他构造函数以及一个返回某个值的函数

foo()
。我想创建一个可以从每个类派生的类模板,并且有一个与
foo()
的返回类型相同类型的数据成员(如果我弄错了一些术语,很抱歉)。

换句话说,我想要一个类模板

template<typename T> class C : public T
{
  footype fooresult;
};

其中

footype
T::foo()
的返回类型。

如果基类都有一个默认构造函数,我就可以做

decltype(T().foo()) fooresult;

(具有 GCC 中的 C++11 功能),但除了复制构造函数之外,这些类没有任何特定的共同构造函数。

GCC 也不允许

decltype(this->foo())
,尽管显然这有可能被添加到 C++0x 标准中 - 有人知道这有多大可能吗?

我觉得应该可以按照

decltype(foo())
decltype(T::foo())
的方式做一些事情,但这些似乎不起作用:GCC 给出了
cannot call member function 'int A::foo()' without object
形式的错误。

当然,我可以有一个额外的模板参数

footype
,甚至是
T
类型的非类参数,但是有什么方法可以避免这种情况吗?

c++ templates c++11 decltype
4个回答
68
投票

你不需要 - 请记住,由于 decltype 不评估其参数,因此你可以直接调用

nullptr

decltype(((T*)nullptr)->foo()) footype;

57
投票

另一种选择是:

#include <utility>

template<typename T> class C : public T
{
   decltype(std::declval<T>().foo()) footype;
};

declval
返回
T&&
。或者,如果 foo 可能被右值引用限定符重载,并且您想确保获得 foo 的左值重载:

   decltype(std::declval<T&>().foo()) footype;

在此示例中

declval
返回
T&

((T*)nullptr)->
解决方案一样,
std::declval
对类型
T
没有要求。


6
投票

也可以使用 C++17 的

std::invoke_result
或它所替代的已弃用的
std::result_of
来完成此操作:

#include <type_traits>

template<typename T> class C : public T
{
    using footype = std::invoke_result_t<decltype(&T::foo), T>;
    footype fooresult;
};

0
投票

还有另一种可能性:只知道类成员函数的类型,不知道类实例或如何调用成员函数,只想从中提取,例如

int (IObject::*)(int, float)
,返回类型
int
,这里有一个简单的例子来演示这种情况:

#include <iostream>
#include <type_traits>

class IObject {
public:
    virtual int foo(int, float) = 0;
    virtual double bar(double) = 0;
};


template<typename T>
struct method_return_type;

template<typename R, typename C, typename... Args>
struct method_return_type<R(C::*)(Args...)> {
    using type = R;
};

template<typename MethodT>
using method_return_type_t = typename method_return_type<MethodT>::type;

template<typename ObjectMethodT>
void some_func() {
    if constexpr (std::is_same_v<method_return_type_t<ObjectMethodT>, int>) {
        std::cout << "do something for int return type" << std::endl;
    } else if constexpr (std::is_same_v<method_return_type_t<ObjectMethodT>, double>) {
        std::cout << "do something for double return type" << std::endl;
    } else
        static_assert(!sizeof(ObjectMethodT) && "unexpected type.");
}

int main() {
    some_func<decltype(&IObject::foo)>();
    some_func<decltype(&IObject::bar)>();
}

method_return_type
只是从成员函数签名中提取返回类型。

如果通过

std::invoke_result_of
,必须指定成员函数
std::invoke_result_t<decltype(&IObject::foo), IObject, int, float>
的参数类型,但函数
some_func
可能不知道这些参数类型是什么。

© www.soinside.com 2019 - 2024. All rights reserved.