Вопрос

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?

Это было полезно?

Решение

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);
//                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top