expr_t is base class, ident_t is derived from expr_t. I wrote some to_string overload to display different expr_t
#include <iostream>
#include <string>
struct expr_t {
virtual ~expr_t() {}
};
struct ident_t : public expr_t {
std::string name;
ident_t(std::string name) : name(name) {}
};
std::string to_string(expr_t& v) {
if (auto* id = dynamic_cast<ident_t*>(&v)) {
return to_string(*id);
}
return "error";
}
std::string to_string(ident_t& v) {
return v.name;
}
int main() {
expr_t* b = new ident_t("c");
std::cout << to_string(*b) << std::endl; // segfault
delete b;
return 0;
}
However, no output, and segfault occurs when debugging with GDB
>Solution :
The problem is that at the point of the call return to_string(*id) the compiler doesn’t have a declaration for the second overload std::string to_string(ident_t& v). Thus the same first version will be recursively called eventually resulting in a seg fault.
To solve this you can either move the second overload’s definition before the first overload or forward declare the second overload before the definition of the first overload as shown below:
//moved the 2nd overload above first overload
std::string to_string(ident_t& v) {
return v.name;
}
std::string to_string(expr_t& v) {
if (auto* id = dynamic_cast<ident_t*>(&v)) {
return to_string(*id); //now compiler knows about std::string to_string(ident_t& v)
}
return "error";
}
Method 2
//forward declaration for 2nd overload
std::string to_string(ident_t& v);
std::string to_string(expr_t& v) {
if (auto* id = dynamic_cast<ident_t*>(&v)) {
return to_string(*id); //now compiler knows about std::string to_string(ident_t& v)
}
return "error";
}
//definition for 2nd overload
std::string to_string(ident_t& v) {
return v.name;
}