63

(如果您是 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 中,我们可以使用autoand来推断模板方法的返回类型: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()))

我想只声明一个辅助方法,它接受 aT&并返回 aT然后定义返回类型doSomethingto decltype(helper(foo.bar()))。但必须有更好的方法,我感觉到了。

4

1 回答 1

63

要删除参考:

#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
}
于 2012-11-02T20:14:56.217 回答