How to boost::any_cast into std::string

10,141

Solution 1

"Mayukh" is not a std::string, it is a const array of 7 characters {'M', 'a', 'y', 'u', 'k', 'h', '\0'}. In C++14, "Mayukh"s is a std::string after using namespace std::literals::string_literals;.

In C++11, std::string("Mayukh") is a std::string as well.

boost::any only supports converting back to the exact same type (well, up to some decay/const/etc). It does not support conversions between the types. See boost any documentation:

Discriminated types that contain values of different types but do not attempt conversion between them, i.e. 5 is held strictly as an int and is not implicitly convertible either to "5" or to 5.0. Their indifference to interpretation but awareness of type effectively makes them safe, generic containers of single values, with no scope for surprises from ambiguous conversions.

Augmenting any with extra smart conversions can be done. For example, a pseudo-any that takes an incoming type, and possibly auto-converts it (so it won't store shorts: it converts all signed integral types to int64_t and unsigned to uint64_t, it converts "hello" to std::string("hello"), etc) before storing it.

Solution 2

That's because "Mayukh" is not a std::string. It's a const char[7], which would decay into const char*:

boost::any a = "Mayukh";
std::cout << a.type().name() << '\n';  // prints PKc, pointer to const char
if (boost::any_cast<const char*>(&a)) {
    std::cout << "yay\n";              // prints yay
}

If you want to be able to use any_cast<std::string>, you'd need to put it in as a std::string:

container.push_back(std::string("Mayukh"));

Solution 3

This is not an answer to the question body but rather to the title to help others who also come here from google:

bool is_char_ptr(const boost::any & operand)
{
    try {
        boost::any_cast<char *>(operand);
        return true;
    }
    catch (const boost::bad_any_cast &) {
        return false;
    }
}

std::string any2string(boost::any anything)
{
    if (anything.type() == typeid(int)) {
        return std::to_string( boost::any_cast<int>(anything) );
    }
    if (anything.type() == typeid(double)) {
        return std::to_string(boost::any_cast<double>(anything));
    }
    if (is_char_ptr(anything)) {
        return std::string(boost::any_cast<char *>(anything));
    }
    if (boost::any_cast<std::string>(anything)) {
        return boost::any_cast<std::string>(anything);
    }

}

The last if looks weird but it works because the function is overloaded.

Share:
10,141
Mayukh Sarkar
Author by

Mayukh Sarkar

Backend Engineer | DataGeek | Gopher | Python Lover

Updated on June 14, 2022

Comments

  • Mayukh Sarkar
    Mayukh Sarkar almost 2 years

    I have this test snippet

    #include <boost/any.hpp>
    #include <iostream>
    #include <vector>
    #include <bitset>
    #include <string>
    
    class wrapper {
      int value;
      char character;
      std::string str;
    
    public:
      wrapper(int i, char c, std::string s) {
        value = i;
        character = c;
        str = s;
       }
    
      void get_data(){
        std::cout << "Value = " << value << std::endl;
        std::cout << "Character = " << character << std::endl;
        std::cout << "String= " << str << std::endl;
      }
    };
    
    int main(){
    
       std::vector<boost::any> container;
       container.push_back(10);
       container.push_back(1.4);
       container.push_back("Mayukh");
       container.push_back('A');
       container.push_back(std::bitset<16>(255) );
       wrapper wrap(20, 'M', "Alisha");
       container.push_back(wrap);
    
       std::cout << boost::any_cast<int>(container[0]) << std::endl;
       std::cout << boost::any_cast<double>(container[1]) << std::endl;
       std::cout << boost::any_cast<std::string>(container[2]);
       std::cout << boost::any_cast<char>(container[3]) << std::endl;
       std::cout << boost::any_cast<std::bitset<16>>(container[4]);
       auto p = boost::any_cast<wrapper>(container[5]);
       p.get_data();
    
    return 0;
    
    }
    

    In this boost::any_cast gives bad_casting exception for std::string. It means for some reason it is not able to typecast boost::any into std::string. While other classes like bitset or my own user defined class is working. Can you please tell me why & a way out of this?

  • Columbo
    Columbo almost 9 years
    Wouldn't it be more correct to say "an std::string"?
  • Praetorian
    Praetorian almost 9 years
    @Columbo I'm with you on that, but there are those who pronounce it as stood string, in which case a is appropriate.
  • sehe
    sehe almost 9 years
    @Columbo It starts with an s, end of story. Abbreviations are abbreviations not meant to be pronounced (they're not acronyms). But thanks for explaining how on earth people come up with that insane juxta-position of "an std::T" some times :)
  • Yakk - Adam Nevraumont
    Yakk - Adam Nevraumont almost 9 years
    @Columbo How do you pronounce std::string to make you think it needs an an?
  • Barry
    Barry almost 9 years
    It's definitely pronounced stood string. That should be in the standard. Under [basic.obviously].
  • Columbo
    Columbo almost 9 years
    @Yakk Well, I pronounce it "s-t-d string"... :D but yeah, if in your mind it's pronounced "stood" then "a" is definitely the right article to use.