Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning value with the same constness as the parameter

Tags:

c++

constants

I have a function with these overloads:

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

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

The return statement can be a much more complicated logic which returns some value that is const if b is const. For example, B is a container of containers (possibly with even deeper nesting) and we are searching for one element. In this case, copying the function is not a good idea. Is there any alternatives for achieving the same result?

I can think of some solutions, but I don't really like them.

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

It works but becomes complicated if that b.a is not so trivial (as in the with in the containers).

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

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

This also works but if feels like a hack. Is there a simple and clean solution?

like image 312
petersohn Avatar asked Oct 04 '13 12:10

petersohn


2 Answers

I would implement non-const version in terms of const version, not the other way round (as you did).

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

It looks a bit safer from mutability point of view.

As for the template version, how about this:

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

If std::conditional_t (C++14) is not supported, then use std::conditional:

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

Hope that helps.

like image 90
Nawaz Avatar answered Sep 23 '22 15:09

Nawaz


A possible solution:

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;
}

EDIT:

C++14 will have function return type deduction, so this should work:

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

gcc 4.8.1 already compiles it.

like image 39
green lantern Avatar answered Sep 26 '22 15:09

green lantern