【问题标题】:Compile error, method with multi assignment to member variable, template class C++编译错误,对成员变量进行多重赋值的方法,模板类 C++
【发布时间】:2016-02-17 06:48:26
【问题描述】:

问题方法:

template <typename T>
    void SerializableScalar<T>::deserialize(const Json::Value& token)
    {
        if (isDeserilizationPossible(token)){

            if (token.isInt())
            {
                myValue = token.asInt();
            }
            if (token.isDouble())
            {
                myValue = token.asDouble();
            }
            if (token.isString())
            {
                myValue = token.asString().c_str();
            }
            if (token.isBool())
            {
                myValue = token.asBool();
            }
        }
    }

其中 token 可以保存类型 string、int、double、bool。

然后我创建对象并使用反序列化方法

Json::Value token(55);

当我创建对象时:

SerializableScalar<int> object;
object.deserialize(token);

我得到编译错误,因为当我创建 T = int; 的对象时在我的反序列化方法中,即使 json 不包含 string 的值,我也无法将 string 转换为 int ,因此编译器会检查所有分支....现在我向您征求意见。有什么解决办法吗?我试图重载反序列化方法,它可以工作,但我不想要单独的 4 个方法,我正在寻找更清洁的方法。

IsDeserilizationPossible 方法

template <typename T>
   bool SerializableScalar<T>::isDeserilizationPossible(const            Json::Value& token)
    {
        if (!token.isArray() && !token.isObject() && !token.empty())
        {
            myIsDeserialize = true;
            return true;
        }

        throw std::exception("Some exception");
    }

其他信息:

在cLass中只是空的构造函数和变量myValue持有T的类型。点是反序列化Json,设置类型T的值。客户端知道他想要获取的类型,所以他使用getMethod获取Serializable对象的值;就是这样,我尝试了专业化,它已经很好了,但我只是好奇是否还有更多我可以使用的东西,所以我不需要重载方法。

错误:

error C2440: '=' : cannot convert from 'const char *' to 'double'   
error C2440: '=' : cannot convert from 'const char *' to 'int'

【问题讨论】:

  • 如果您包含编译器错误以及可能对 SerializableScalar 进一步的类定义,将会很有帮助。 myValue 是什么?
  • 已更新,包括错误
  • 真的没有办法。您将不得不为您关心的每个T 编写模板专业化。但是,您可以专门针对类型的“组”。请在此处查看我的答案以供参考:stackoverflow.com/a/34111729/1142167
  • 基本上,没有办法确保在编译时你的 if 语句的任何分支都会在运行时被遍历。这就是你的编译器阻塞的原因。例如,它无法提前知道token.isInt() 是否会仅针对ints 返回true

标签: c++ c++11 visual-c++ c++14


【解决方案1】:

不幸的是,没有办法为每种相关类型创建专业化。这是将特化委托给辅助类的一种方法:

template<typename T>
struct Helper
{
    static inline bool is(const Json::Value&);
    static inline T as(const Json::Value&);
};

template<> bool Helper<int>::is(const Json::Value& tok)
{ return tok.isInt(); }

template<> bool Helper<double>::is(const Json::Value& tok)
{ return tok.isDouble(); }

template<> bool Helper<string>::is(const Json::Value& tok)
{ return tok.isString(); }

template<> bool Helper<bool>::is(const Json::Value& tok)
{ return tok.isBool(); }

template<> int Helper<int>::as(const Json::Value& tok)
{ return tok.asInt(); }

template<> double Helper<double>::as(const Json::Value& tok)
{ return tok.asDouble(); }

template<> string Helper<string>::as(const Json::Value& tok)
{ return tok.asString(); }

template<> bool Helper<bool>::as(const Json::Value& tok)
{ return tok.asBool(); }

template<typename T>
void SerializableScalar<T>::deserialize(Json::Value& tok)
{
    if ( Helper<T>::is(tok) )
        myValue = Helper<T>::as(tok);
}

【讨论】:

  • 实际上看起来没有那么糟糕,我喜欢这个解决方案。谢谢
【解决方案2】:

这应该是评论,但是太长了:

这种方法的问题

编译时和运行时的数量不能很好地结合在一起。我猜您已经发现将类型 int 硬编码到您的序列化中是很不舒服的。

SerializableScalar<int> object;

如果它包含一个字符串呢?您想反序列化每种可能的类型吗?

SerializableScalar<int> object_int;
SerializableScalar<double> object_double;
SerializableScalar<std::string> object_string;

if(object_int)  //check whether int is filled
{
    //...
}
else if (object_double)
{
    //...
}

接下来,您是否要递归执行此操作(Json 可以包含其他 Json)?这在我看来是不切实际的。

异常:Json 的内容在编译时是已知的

唯一的例外是您确切知道 Json 的内容的情况。然后,可以编写一个通用的包装器 function (这比 imo 类更舒服),例如

template<typename T>
auto get_value(Json::Value const& json) {}

template<>
auto get_value<int>(Json::Value const& json) { return json.as_int(); }

template<>
auto get_value<bool>(Json::Value const& json) { return json.as_bool(); }

并根据您的 Json 的结构应用它。请注意,到目前为止,我还没有添加任何类型检查,例如 json.is_int()。合并它的两种可能性:

  • 首先,如果不是int,返回一个默认值:

    constexpr int DEFAULT = -1;
    template<>
    auto get_value<int>(Json::Value const& json)
    {
        return json.is_int() ? json.as_int() : DEFAULT;
    }
    
  • 其次,更复杂一点,你可以返回一个optional&lt;int&gt;,如果json没有被填充,它就处于空状态。

一般情况

然而,在一般情况下,当您不知道内容或内容即将更改时,您必须接受 Json 的多类型存在并相应地对其进行建模。基本方法是使用boost::variant 加上适当的visitor

【讨论】:

  • 谢谢,看起来不错,我知道json的内容,json只是单值
【解决方案3】:

一种可能性是创建一个包罗万象的重载:

void Json::Value::operator=(...)
{
    assert( false && "this should never be called" );
}

这将在重载解决方案中具有最低优先级,但是敏感的分配将不再产生编译时错误,因此请考虑它是一种快速修复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-28
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-20
    • 2017-02-19
    相关资源
    最近更新 更多