boost::variant - why is "const char*" converted to "bool"?

This has nothing to do with boost::variant, but with the order in which C++ selects the conversions to apply. Before trying to use user-defined conversions (remember that std::string is a user-defined class for this purpose), the compiler will try built-in conversions. There is no built-in conversion from const char* to int, but according to §4.12 in the standard:

A prvalue of [...] pointer [...] type can be converted to a prvalue of type bool.

So the compiler happily converts your const char* to a bool and never gets to consider converting it to a std::string.

UPDATE: It looks like this clearly unwanted conversion is being fixed. You can find a technical explanation of the fix here.


I don't think this is anything particularly to do with boost::variant, it's about which constructor gets selected by overload resolution. The same thing happens with an overloaded function:

#include <iostream>
#include <string>

void foo(bool) {
    std::cout << "bool\n";
}

void foo(std::string) {
    std::cout << "string\n";
}

int main() {
    foo("hi");
}

output:

bool

I don't know of a way to change what constructors a Variant has [edit: as James says, you can write another class that uses the Variant in its implementation. Then you can provide a const char* constructor that does the right thing.]

Maybe you could change the types in the Variant. Another overloading example:

struct MyBool {
    bool val;
    explicit MyBool(bool val) : val(val) {}
};

void bar(MyBool) {
    std::cout << "bool\n";
}

void bar(const std::string &) {
    std::cout << "string\n";
}

int main() {
    bar("hi");
}

output:

string

Unfortunately now you have to write bar(MyBool(true)) instead of foo(true). Even worse in the case of your variant with string/bool/int, if you just change it to a variant of string/MyBool/int then MyVariant(true) would call the int constructor.