0

I'm using the function tryValue very often in my projects. It is simple wrapper around boost::any, that simplifies greatly its everyday usage.

#include <boost/optional.hpp>
#include <boost/any.hpp>
#include <boost/optional/optional_io.hpp>
#include <iostream>

template<typename T>
boost::optional<T> tryValue(const boost::any& any) {
    try {
        boost::optional<T> ret(boost::any_cast<T>(any));
        return ret;
    }
    catch (...) {
    }
    return boost::none;
}

template<typename T>
boost::optional<T> tryValueRef(boost::any& any) {
    try {
        boost::optional<T> ret(boost::any_cast<T>(any));
        return ret;
    }
    catch (...) {
    }
    return boost::none;
}

int main(int, char**) {
    boost::any x(5);
    auto u = tryValue<int>(x);
    u = 6;
    std::cout << boost::any_cast<int>(x) << std::endl;

    auto r = tryValueRef<int&>(x);
    *r = 8; // Here I need a *? Why is that?
    std::cout << boost::any_cast<int>(x) << std::endl;
}

Now, I extended this function, so that I can deal with reference. This has the opportunity to change the value inside my boost-optional in place.

Now it is tiresome to keep in mind, if I have to write tryValue or tryValueRef. The function tryValue should figure out on its own, whether T is a reference (or even pointer) or not. The template function std::is_reference<T> should do this job, but I have no idea how to effectively use it.

A second part, that I don't understood yet, is why the return value of tryValueRef needs an extra * to set the value.

Solution

A simple renaming of the function was sufficient to make it work.

template<typename T>
boost::optional<T> tryValue(const boost::any& any) {
    try {
        boost::optional<T> ret(boost::any_cast<T>(any));
        return ret;
    }
    catch (...) {
    }
    return boost::none;
}

template<typename T>
boost::optional<T> tryValue(boost::any& any) {
    try {
        boost::optional<T> ret(boost::any_cast<T>(any));
        return ret;
    }
    catch (...) {
    }
    return boost::none;
}

int main(int, char**) {
    boost::any x(5);
    auto u = tryValue<int>(x);
    u = 6;
    std::cout << boost::any_cast<int>(x) << std::endl;

    auto v = tryValue<int&>(x);
    *v = 7;
    std::cout << boost::any_cast<int>(x) << std::endl;
}
Aleph0
  • 5,816
  • 4
  • 29
  • 80
  • What's the problem when both functions have the same name and you let overload resolution take part? – DeiDei Jun 05 '18 at 07:09
  • 2
    @DeiDei: with overloaded resolution, the compiler will not take the overloaded function that you intent, but the one based on the context of the caller: if the parameter is not const, it will call the non-const parameter function. – stefaanv Jun 05 '18 at 07:17
  • @DeiDei: You where correct. I just renamed my function and it works like charm. I'll post my solution. – Aleph0 Jun 05 '18 at 07:21
  • Still, I don't know why I need the extra `*`, if the second function is called. – Aleph0 Jun 05 '18 at 07:23
  • 1
    the reason you need * here is that you are casting to int& and v is a pointer to int. so to change its value you need *v. inside tryValue you construct boost::optional which does not take a reference argument. – Nir Jun 05 '18 at 07:24
  • @Nir: Thanks for your explanation. :-) – Aleph0 Jun 05 '18 at 07:26
  • @Aleph0 see also any_cast related question here: https://stackoverflow.com/questions/41905868/stdany-cast-returns-a-copy – Nir Jun 05 '18 at 07:31

0 Answers0