5

我有一个带有这些重载的函数:

A& f(B& b)
{
    return b.a;
}

const A& f(const B& b)
{
    return b.a;
}

return 语句可以是一个更复杂的逻辑,如果b是 const,它会返回一些 const 值。例如,B是一个容器容器(可能具有更深的嵌套),我们正在搜索一个元素。在这种情况下,复制函数不是一个好主意。是否有任何替代方法可以达到相同的结果?

我可以想到一些解决方案,但我不是很喜欢它们。

template <typename T>
auto f(T& b) -> decltype(b.a)
{
    return b.a;
}

它可以工作,但如果b.a不是那么微不足道(如容器中的 with ),它就会变得复杂。

A& f(B& b)
{
    return b.a;
}

const A& f(const B& b)
{
    return f(const_cast<B&>(b));
}

这也有效,但如果感觉像一个黑客。有没有简单干净的解决方案?

4

3 回答 3

3

我会根据 const 版本来实现非 const 版本,而不是反过来(就像你所做的那样)。

A& f(B& b)
{
    return const_cast<A&>(f(static_cast<B const&>(b)));
}

从可变性的角度来看,它看起来更安全一些。

至于模板版本,这个怎么样:

template <typename T>
auto f(T& b) -> std::conditional_t<std::is_const<T>{}, A const&, A&>
{
    return b.a;
}

如果std::conditional_t不支持 (C++14),则使用std::conditional

typename std::conditional<std::is_const<T>{}, A const&, A&>::type

希望有帮助。

于 2013-10-04T12:27:18.487 回答
2

如果您知道这f不会改变数据,那么这const_cast不是黑客攻击,而是一个完全合法的解决方案。

典型的例子是strchr,它在字符串中查找一个字符。我们知道这不会发生变异,但是通过提供非常量重载来允许可变字符串发生变异是完全明智的。但是,非常量版本可以很高兴地根据 const 重载来实现。

请记住,使用const_cast. 改变一个常量object只是一种违规行为。

于 2013-10-04T12:21:39.597 回答
2

一个可能的解决方案:

template<typename B>
struct Return_type { typedef A &Type; };

template<typename B>
struct Return_type<B const &> { typedef A const &Type; };

template<typename B>
typename Return_type<B>::Type f(B &&b)
{
    return b.a;
}

编辑:

C++14 将有函数返回类型推导,所以这应该有效:

template<typename T>
auto &f(T &&b)
{
    return b.a;
}

gcc 4.8.1 已经编译了它。

于 2013-10-04T12:47:00.193 回答