Hariom Singh
Hariom Singh

Reputation: 3632

bad_variant_access not working

I am trying to get a std::bad_variant_access exception when the variant is not in the list .But the below code doesn't work it returns a implicit converted ASCII int value

what changes should I do that variant is strict on type selection

#include <iostream>
#include <variant>
using namespace std;

struct printer
{
    void operator()(int x) {
        cout << x << "i"<<endl;

    }
    void operator()(float x) {
        cout << x << "f"<<endl;
    }
    void operator()(double x)
    {
        cout << x << "d" << endl;;
    }
};
int main() {

    using my_variant = std::variant<int, float, double>;
    my_variant v0('c');

    try {
        std::visit(printer{}, v0);
        }

    catch(const std::bad_variant_access& e) {
        std::cout << e.what() << '\n';
    }

    return 0;
}

Output:

99i

Whereas I was expecting to get std::bad_variant_access exception

Code

Upvotes: 2

Views: 3587

Answers (2)

AndyG
AndyG

Reputation: 41110

std::visit will only trigger a bad_variant_access exception if the variant is valueless_by_exception (C++17, see N4659 23.7.3.5 [variant.status] )

What this means is that if you tried to set a variant value in a fashion that throws an exception, the variant is left in a "valueless" state, so visitation is not permitted.

To trigger it, we can change the code like so:

struct S{

    operator int() const{throw 42;}
};

struct printer{//as before};

int main() {
    using my_variant = std::variant<int, float, double>;
    my_variant v0{'c'};

    try{
       v0.emplace<0>(S());
    }catch(...){}

    try {
        std::visit(printer{}, v0);
    }
    catch(const std::bad_variant_access& e) {
        std::cout << e.what() << '\n';
    }
}

Demo

Frank already answered why you could construct your variant in the first place using a char (construction chosen via overload).

You can not trigger a bad_variant_access by attempting to first construct a variant in a fashion that will throw because [variant.ctor] dictates that the constructor will rethrow that exception (in this case int).

Upvotes: 3

user4442671
user4442671

Reputation:

According to the documentation for std::variant:

That constructor of variant does the following:

Constructs a variant holding the alternative type T_j that would be selected by overload resolution for the expression F(std::forward(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types... in scope at the same time. [...]

I.e. std::variant will get the first type that is constructible from the passed argument. In this case, int is constructible from a char, so the variant gets assigned as such.

Upvotes: 2

Related Questions