如何比较给定指针和类型的两个值

Ein*_*and 6 c++

假设我有一个存储一些数据的类,

class Value {
public:
    enum class Type {
        int_type,
        float_type,
        double_type,
        bool_type
    };

    friend bool operator==(const Value& lhs, const Value& rhs) {
        //  how to make this function clean and concise?
    }

private:
    void* ptr;
    Type type;
};
Run Code Online (Sandbox Code Playgroud)

ptr指向基础值并type指示ptr应如何转换。

为了比较Value对象,我绝对可以列出所有可能的类型组合,但是代码将很难维护。喜欢:

if (lhs.type == Type::int_type && rhs.type == Type::float_type) {
    return *static_cast<int*>(lhs.ptr) == *static_cast<float*>(rhs.type);
}
Run Code Online (Sandbox Code Playgroud)

任何想法如何减少复杂性?

更新

我希望此类为动态类型,这意味着我可以执行以下操作:

Value v("abc");       // v is now a string
v = 123;              // v is now an int
bool b = (v == 123.0); // b is true
Run Code Online (Sandbox Code Playgroud)

因此,我认为模板可能不会有所帮助。

Ric*_*ges 2

实际上,您想要做的是编写弱类型。

此类类型是 python 和 javascript 等脚本语言的基础。

编写这样的类型比您最初想象的要复杂。

但是,一旦定义了转换矩阵,事情就会变得更容易(例如,比较字符串与布尔值的规则是什么?)

这是一个开始,使用std::variant

#include <variant>
#include <string>
#include <type_traits>
#include <algorithm>
#include <cassert>

//
// Step 1 - define your conversion rules
//          this is not as trivial as you might think
//

template<class To>
struct convert;

template<>
struct convert<int>
{
    template<class From>
    auto operator()(From const& from) const -> int
    {
        return int(from);
    }
    auto operator()(std::string const& from) const -> int
    {
        return std::atoi(from.c_str());
    }
};
template<>
struct convert<double>
{
    template<class From>
    auto operator()(From const& from) const -> double
    {
        return double(from);
    }
    auto operator()(std::string const& from) const -> double
    {
        return std::atof(from.c_str());
    }
};
template<>
struct convert<bool>
{
    template<class From>
    auto operator()(From const& from) const -> bool
    {
        return bool(from);
    }
    auto operator()(std::string  from) const -> bool
    {
        auto lcase = [](auto ch) { return std::tolower(ch); };
        std::transform(from.begin(), from.end(), from.begin(), lcase);
        if (from == "true" || from == "yes" || std::atoi(from.c_str()))
            return true;
        else
            return false;
    }
};
template<>
struct convert<std::string>
{
    template<class From>
    auto operator()(From const& from) const -> std::string
    {
        return std::to_string(from);
    }

    auto operator()(bool const& from) const -> std::string
    {
        auto result = std::string();
        if (from)
            result.assign("true");
        else
            result.assign("false");
        return result;
    }

    auto operator()(std::string const& from) const -> std::string const&
    {
        return from;
    }
};

//
// Step 2 - use a std::variant
//

struct Value 
{
    explicit Value(int arg): store_(arg) {}
    explicit Value(double arg): store_(arg) {}
    explicit Value(bool arg): store_(arg) {}
    explicit Value(std::string arg): store_(std::move(arg)) {}
    explicit Value(const char* arg): store_(std::string(arg)) {}

    friend bool operator==(const Value& lhs, const Value& rhs) 
    {
        auto compare = [](auto &&l , auto&& r) 
        { 
            using l_type = std::decay_t<decltype(l)>;
            auto conv = convert<l_type>();
            return l == conv(r);
        };
        return std::visit(compare, lhs.store_, rhs.store_);
    }

private:
    using storage_type = std::variant<int, double, bool, std::string>;

private:
    storage_type store_;
};

int main()
{
    auto vt = Value(true);
    auto vst = Value("true");
    assert(vt == vst);
}
Run Code Online (Sandbox Code Playgroud)