(如果你是C ++ 11专业版,请跳到粗体段落。)
让我们说我想编写一个模板方法,该方法调用并返回传递对象的结果,该对象的类型是模板参数:
template<ReturnType, T>
ReturnType doSomething(const T & foo) {
return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}
所以T
必须有一个方法ReturnType T::bar() const
才能在这样的调用中使用:
struct MyClass {
...
int bar() const;
...
};
...
MyClass object;
int x = doSomething<int, MyClass>(object);
由于类型扣除而我们不必写MyClass
并且电话会变成:
int x = doSomething<int>(object);
但是省略<int>
也会导致编译错误,因为该方法不需要返回int以便之后被分配给x
(它可以返回char
例子)。
在C ++ 0x / 11中,我们使用auto
和decltype
来推断模板方法的返回类型:
template<T>
auto doSomething(const T & foo) -> decltype(foo.bar()) {
return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}
编译器现在将找出foo.bar()
的类型,并将其用作返回类型。使用我们的具体课程MyClass
,这将是int
,以下就足够了:
int x = doSomething(object);
现在问我的问题:
如果MyClass将bar()
定义为返回int&
,则doSomething(object)
的返回类型也将是int&
= decltype(foo.bar())
。这是一个问题,因为G ++现在符合我返回对临时的引用。
我该如何解决这个问题?是否有类似remove_reference
的内容可以像remove_reference(decltype(foo.bar()))
一样使用?
我考虑过只声明一个帮助方法,该方法接受T&
并返回T
,然后将doSomething
的返回类型定义为decltype(helper(foo.bar()))
。但必须有更好的方式,我感觉到它。
答案 0 :(得分:51)
删除引用:
#include <type_traits>
static_assert(std::is_same<int, std::remove_reference<int&>::type>::value, "wat");
在你的情况下:
template <typename T>
auto doSomething(const T& foo)
-> typename std::remove_reference<decltype(foo.bar())>::type
{
return foo.bar();
}
为了清楚起见,请注意,在书面回复时,参考就可以了:
#include <type_traits>
struct f
{
int& bar() const
{
static int i = 0;
return i;
}
};
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar();
}
int main()
{
f x;
return doSomething(x);
}
返回的引用可以简单地传递而不会出错。您在评论中的示例是重要且有用的地方:
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar() + 1; // oops
}