Search code examples
c++c++17conditional-operatorvariantstd-variant

Weird result of std::variant


I'm struggling with an odd behavior of the below code. The problem is that output of this snippet is "double". But we have an int in lhs.

I dug for a while and figured out the compiler put a garbage double value into var for some reason. Then this turned the type of the variable into double. This breaks all my code at the outer scope, because I do some operations according to the type of the variable.

What am I missing? Is it supposed to work like this?

std::variant<int, double> lhs = 4;

auto var = std::holds_alternative<int>(lhs) ? std::get<int>(lhs) : std::get<double>(lhs);

if (std::strcmp(typeid(var).name(), "i") == 0)
    std::cout << "int";
else
    std::cout << "double";

Solution

  • std::variant<int, double> lhs = 4;
    

    so lhs is a variant holding either an int or a double. As you stored an int in it, it holds an int.

    auto var = std::holds_alternative<int>(lhs) ? std::get<int>(lhs) : std::get<double>(lhs);
    

    this is the same as

    auto var = true ? std::get<int>(lhs) : std::get<double>(lhs);
    

    which is

    auto var = true ? (int)4 : double(3.14);
    

    The type of var is computed to be double, but its value is 4.

    double var = 4;
    

    auto is not a runtime dynamic type; it is a compile time computed type.

    if (std::strcmp(typeid(var).name(), "i") == 0)
      std::cout << "int";
    else
      std::cout << "double";
    

    which prints "double".

    I think what you want to do is this:

    std::variant<int, double> lhs = 4;
    
    std::visit( [&](auto var){
      if (std::strcmp(typeid(var).name(), "i") == 0)
        std::cout << "int";
      else
        std::cout << "double";
    }, lhs);
    

    which prints "int" as expected.

    Here, we create a visitor function. std::visit makes a runtime switch to decide which type lhs contains, and calls the one that matches the type within lhs.

    Be careful, because both versions of the lambda function are instantiated, but only one is called.