Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast a value using decltype, is it possible?

Is it possible to use decltype to cast a value?

For example let's say that we have the following template:

template<typename Container>
auto findInposition(Container& c,int position)->decltype(*(c.begin()))
{
  if(std::distance(c.begin(),c.begin()+position)<c.size())
  return c.at(p);
  /*else
    return decltype(*(c.begin())(somevalue);*/
}

which returns the value of an Item at a specific position in a Container. Let's say that the user enters a position greater than the size of the container, in this situation I want to return a casted value, let's say a casted zero or something. I don't know if my example is good enough, my main question is: Is it possible to cast a value using decltype and if yes how?

like image 930
Avraam Mavridis Avatar asked May 22 '13 08:05

Avraam Mavridis


People also ask

What is the use of decltype in C++?

The decltype type specifier yields the type of a specified expression. The decltype type specifier, together with the auto keyword, is useful primarily to developers who write template libraries. Use auto and decltype to declare a function template whose return type depends on the types of its template arguments.

Should I use decltype?

Another thing to consider is that decltype isn't really necessary unless you're writing library code, auto is nice for everyday programming if you want to make your code more concise, it's up for debate wether using as much auto as possible is good, but it's virtually necessary when working with unutterable types like ...


1 Answers

In general, you can do it. For instance:

int i = 0;
double d = 3.14;
i = static_cast<decltype(i)>(d);

However, keep in mind your function returns a reference (because decltype(*(c.begin())) evaluates to a reference type):

std::vector<int> v;
static_assert(std::is_same<decltype(*v.begin()), int&>::value, "!"); // Won't fire

What's troublesome in this situation is that the function must be able to return a reference to an object of type Container::value_type, but if somevalue has a different type, you won't be able to return a reference to it as a Container::value_type&.

The reason is the same why you are not allowed to do the following:

int i = 42;
float& f = static_cast<float&>(i);

So the first thing you need to ask yourself is whether your findInposition() function should really return a reference to the element of the collection (in which case, what you want to do is not possible, just like the example above), or rather return by value a copy of that element.

If that is the case, and you insist on using decltype, you may transform the output of decltype through std::decay:

#include <type_traits>

template<typename Container>
auto findInposition(Container& c,int position) ->
    typename std::decay<decltype(*c.begin())>::type
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
  if(std::distance(c.begin(),c.begin()+position)<c.size())
    return c.at(position);
  else
    return static_cast<
        typename std::decay<decltype(*c.begin())>::type>(somevalue);
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

But in my opinion the following is much clearer:

template<typename Container>
auto findInposition(Container& c,int position) ->
    typename Container::value_type
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
  if(std::distance(c.begin(),c.begin()+position)<c.size())
    return c.at(position);
  else
    return static_cast<typename Container::value_type>(somevalue);
//                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
like image 55
Andy Prowl Avatar answered Oct 06 '22 07:10

Andy Prowl