【发布时间】:2012-10-23 12:41:22
【问题描述】:
(如果您是 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()))。但必须有更好的方法,我感觉到了。
【问题讨论】:
-
这是怎么回事?您所要做的就是传递参考。是的,有
std::remove_reference<T>::type。 -
@GManNickG 我不想在我的程序中出现警告。我想用
-Werror -Wall编译。感谢std::remove_reference的提示,我知道我以前见过这个,但是在搜索“c++11 模板类型推导删除参考”时在 google 上找不到它,可能是我的搜索过于本地化了 :) -
不,我是说根本不应该有警告。如果
foo.bar()返回一个引用,您应该也可以将它作为引用返回。 -
啊,是的,在这种情况下。
foo.bar()是一个不好的例子,比如说return foo.bar() + 1。在我的情况下,我正在使用迭代器并想推断出具有begin()的提供容器类型的T,所以我的decltype 是decltype(*container.begin()),即T&。由于我返回了一个临时的T我需要删除引用。 -
很公平,我将把这个区别添加到我的答案中。
标签: c++ templates c++11 type-deduction