1
#include <iostream>
#include <any>
#include <string>
#include <vector>
#include <map>
using namespace std;

string AnyPrint(const std::any &value)
{   
    cout << size_t(&value) << ", " << value.type().name() << " ";
    if (auto x = std::any_cast<int>(&value)) {
        return "int(" + std::to_string(*x) + ")";
    }
    if (auto x = std::any_cast<float>(&value)) {
        return "float(" + std::to_string(*x) + ")";
    }
    if (auto x = std::any_cast<double>(&value)) {
        return "double(" + std::to_string(*x) + ")";
    }
    if (auto x = std::any_cast<string>(&value)) {
        return "string(\"" + (*x) + "\")";
    }
    if (auto x = std::any_cast<char*>(&value)) {
        return string(*x);
    }
}

int main()
{
    int a = 1;
    float b = 2;
    double c = 3;
    string d = "4";
    char *e = "555";
    
    cout << AnyPrint(a) << "\n";
    cout << AnyPrint(b) << "\n";
    cout << AnyPrint(c) << "\n";
    cout << AnyPrint(d) << "\n";
    cout << AnyPrint("555") << "\n";
    cout << AnyPrint(e) << "\n";
    return 0;
}

I'm trying to make a function that converts a std::any object to string, given that the list of possible types is hard-coded. However, there's a problem when user parse raw string like AnyPrint("555"). I use the method from Checking std::any's type without RTTI

I got the following output when I run the program:

140722480985696, i int(1)
140722480985696, f float(2.000000)
140722480985696, d double(3.000000)
140722480985696, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE string("4")
140722480985696, PKc string("4")
140722480985696, Pc 555

How can I handle a std::any of raw string? I don't want to write AnyPrint("555"s) unless it's the only way.

Edit: I use this to run the example https://www.onlinegdb.com/online_c++_compiler

Huy Le
  • 1,439
  • 4
  • 19
  • I would rather implement this using templates and specializations rather. – Victor Mar 31 '22 at 09:46
  • How do you use template on `std::any` though? The input being `std::any` is a requirement, since it's the output from another library – Huy Le Mar 31 '22 at 09:47
  • If you're using `using namespace std;` (which is often adviced against), you should at least use is consistently and have `string AnyPrint(const any &value)`, `if (auto x = any_cast(&value))` etc. – hyde Mar 31 '22 at 09:47
  • 1
    @hyde I'm aware of this. I just use it in examples to make everything short – Huy Le Mar 31 '22 at 09:49
  • Also, `AnyPrint` is missing return statement in case none of the `if` match. It must always return something. – hyde Mar 31 '22 at 09:52
  • (never mind about the if stuff in deleted comment, I re-read the docs...) – hyde Mar 31 '22 at 09:53
  • 1
    Type of `"555"` is `const char[4]` which might decays to `const char*`. You handle `char*`, not `const char*`. – Jarod42 Mar 31 '22 at 09:54
  • 1
    if the number of types to be used is fixed you do not need `std::any`. `std::variant` seems more appropriate – 463035818_is_not_an_ai Mar 31 '22 at 09:55
  • 2
    `char *e = "555";` is not allowed since C++11. It must be `const char*` – 463035818_is_not_an_ai Mar 31 '22 at 09:56
  • I don't quite get what behavior you are *expecting* here, or what you *want* to happen instead of what is actually happening? – DevSolar Mar 31 '22 at 09:58
  • @DevSolar its not explicit in the question, but one line of output is missing due to undefined behavior because `AnyPrint("555")` does not return – 463035818_is_not_an_ai Mar 31 '22 at 10:02
  • 2
    Add `return "Oh dear!";` at the end of `AnyPrint`. (When something can't happen, it usually will.) – molbdnilo Mar 31 '22 at 10:03
  • @molbdnilo thanks I already have that, I forgot to copy that part into the question sample code – Huy Le Mar 31 '22 at 10:04
  • where did `140722480985696, PKc string("4")` come from? – 康桓瑋 Mar 31 '22 at 10:08
  • @康桓瑋 `cout << AnyPrint(d) << "\n";` – 463035818_is_not_an_ai Mar 31 '22 at 10:13
  • @463035818_is_not_a_number. Ok. Then where did `140722480985696, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE string("4") `come from? – 康桓瑋 Mar 31 '22 at 10:14
  • @康桓瑋 you can try running code on the link in the post. `140722480985696` is address of `const std::any &value` – Huy Le Mar 31 '22 at 10:15
  • I mean why would the result of `cout << AnyPrint("555") << "\n"` be `140722480985696, PKc string("4")`? Your link doesn't have any code, I'm pretty sure I won't get this result using your code in OP. What do you expect to get? and what do you actually get? – 康桓瑋 Mar 31 '22 at 10:20

2 Answers2

6

Type of "555" is const char[4] which might decays to const char*. You handle char*, but not const char*.

Handling const char* fixes your issue:

std::string AnyPrint(const std::any &value)
{   
    std::cout << size_t(&value) << ", " << value.type().name() << " ";
    if (auto x = std::any_cast<int>(&value)) {
        return "int(" + std::to_string(*x) + ")";
    }
    if (auto x = std::any_cast<float>(&value)) {
        return "float(" + std::to_string(*x) + ")";
    }
    if (auto x = std::any_cast<double>(&value)) {
        return "double(" + std::to_string(*x) + ")";
    }
    if (auto x = std::any_cast<std::string>(&value)) {
        return "string(\"" + (*x) + "\")";
    }
    if (auto x = std::any_cast<const char*>(&value)) {
        return *x;
    }
    return "other";
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
4

As mentioned in the comments, string literals like "555" are (or decay to) const char* pointers. Your AnyPrint function doesn't handle such an argument type.

Adding the following block fixes the problem:

    if (auto x = std::any_cast<const char*>(&value)) {
        return string(*x);
    }

Also, note that the line, char *e = "555"; is illegal in C++; you need either const char *e = "555"; or char e[] = "555";; using the latter will demonstrate the difference between the char* (with AnyPrint(e)) and const char* (with AnyPrint("555")) types in the std::any_cast<T> blocks.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83