我有一个带有这些重载的函数:
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));
}
这也有效,但如果感觉像是黑客。有简单而干净的解决方案吗?
答案 0 :(得分: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
希望有所帮助。
答案 1 :(得分:2)
如果您知道f
不会改变数据,那么const_cast
不是黑客攻击,而是完全合法的解决方案。
典型的示例是strchr
,它在字符串中查找字符。我们知道这不会发生变异,但允许通过提供非常量重载来突变可变字符串是完全合理的。但是,非const版本可以很好地实现const过载。
请记住,使用const_cast
并不违规。改变常量对象只是违规行为。
答案 2 :(得分: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已编译它。