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?
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.
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 ...
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);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With