我有许多无法修改的类。每个构造函数都有一个复制构造函数、至少一个其他构造函数以及一个返回某个值的函数
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
类型的非类参数,但是有什么方法可以避免这种情况吗?
你不需要 - 请记住,由于 decltype 不评估其参数,因此你可以直接调用
nullptr
。
decltype(((T*)nullptr)->foo()) footype;
另一种选择是:
#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
没有要求。
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;
};
还有另一种可能性:只知道类成员函数的类型,不知道类实例或如何调用成员函数,只想从中提取,例如
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
可能不知道这些参数类型是什么。