【问题标题】:Why won't this compile in VS Express 2013, though it compiles in MinGW?为什么它不能在 VS Express 2013 中编译,尽管它在 MinGW 中编译?
【发布时间】:2014-09-02 05:52:47
【问题描述】:

这是我从几个头文件拼接在一起的可编译示例。代码没有意义,因为我删除了所有不相关的部分,但要点是我正在实现 Scott Meyers 的数据代理技术(提到here),尽管它已经演变成更多的包装器而不是临时代理。不过,这些都不重要——我的问题似乎纯粹是关于编译器行为的差异。

#include <iostream>
#include <vector>

template<typename T>
class Proxy
{
public:
    enum class State
    {
        NEVER_SET = 0,
        SET,
        UNSET
    };
    operator const T& () const
    {
        if ( _state != State::SET )
        {
            std::cout << "EXCEPTION" << std::endl;
            // TODO throw exception
        }
        return _data;
    }
    Proxy<T>& operator=(const T& val)
    {
        _data = val;
        _state = State::SET;
        return (*this);
    }
    Proxy<T>& operator+=(const T& val)
    {
        _data = (*this) + val;
        _state = State::SET;
        return (*this);
    }
private:
    T _data;
    State _state = State::NEVER_SET;
};

class Tape
{
};

template<typename T>
class tape : public Tape
{
public:
    const Proxy<T>& operator[](int idx) const
    {
        return operator[](idx);
    }
    Proxy<T>& operator[](int idx)
    {
        if ( idx >= data.size() )
        {
            data.resize(idx + 1);
        }
        return data[idx];
    }
private:
    std::vector< Proxy<T> > data;
};

class CRIXUS
{
public:
    virtual void Go() final {};
protected:
    virtual void Pre() {};
    virtual void Post() {};
    virtual void Step() = 0;
};

class CRIXUS_MA : public CRIXUS
{
public:
    int window = 30;
    tape<double> input;
    tape<double> output;
protected:
    virtual void Step()
    {
        double sum = 0;
        for ( int j = 0; j < window; j++ )
        {
            sum += input[-j];
        }
        output[0] = sum / window;
    }
};

int main()
{
}

它可以在 Ideone 以及 Jetbrain 的 CLion 上正常编译(工具链:MinGW 3.20,CMake 2.8.12.2):

但是它不会在 VS Express 2013 上编译:

运行 CLion 的完整代码(包括读取 .csv 数字文件并输出移动平均值),我可以验证输出是否正确。只是VS不会编译代码。

据我所知,演员表操作员

    operator const T& () const
    {
        if ( _state != State::SET )
        {
            std::cout << "EXCEPTION" << std::endl;
            // TODO throw exception
        }
        return _data;
    }

应该将Proxy&lt;T&gt; 转换为T Proxy&lt;double&gt; 转换为double。而当我强行投出违规的台词时,

        sum += (double)input[-j];

它工作正常。有什么想法吗?

【问题讨论】:

  • 第86行是哪一行?
  • 啊,对不起。这是sum += input[-j];。在那里,input[-j] 应该返回一个Proxy&lt;double&gt;,但由于sumdouble,我希望会发生转换。
  • @AndrewCheong:找到这个:stackoverflow.com/questions/4622330/…
  • 显然 MSVC 拒绝在此代码中实例化 Proxy&lt;double&gt;。在CRIXUS_MA 的定义之前添加Proxy&lt;double&gt; p; 会强制实例化,并导致代码编译。
  • @EdS。实际上,这种情况下的重载解析将使用内置运算符并执行从Proxy&lt;double&gt;double 的转换。

标签: c++ compiler-errors visual-studio-2013 mingw visual-studio-express


【解决方案1】:

这似乎是更多的 MSVC 模板损坏。它拒绝在这段代码中实例化Proxy&lt;double&gt;,导致重载解析失败。只需在CRIXUS_MA 的定义之前添加Proxy&lt;double&gt; p;,这会强制进行隐式实例化,就足以使代码编译。根据§14.7.1 [temp.inst]/p6:

一个类模板特化被隐式实例化,如果 类类型在需要完全定义的上下文中使用 对象类型或类类型的完整性可能会影响 程序的语义。 [ 注意:特别是,如果 表达式依赖于类的成员或基类列表 模板特化,类模板特化是 隐式生成。例如,删除指向类类型的指针 取决于类是否声明了析构函数,并且 指向类类型的指针之间的转换取决于继承 所涉及的两个类之间的关系。 —尾注 ]

由于sum += input[-j];的语义显然依赖于Proxy&lt;double&gt;的定义,它应该已经被隐式实例化了。

【讨论】:

  • 谢谢;我正要根据您的建议发布,我将Proxy&lt;T&gt; dummy 添加为class tape 的成员,并且成功了。 (我不想手动指定 double 和其他原语。)不过,关于成员与非成员运算符的 cmets 似乎非常引人注目。你认为它们与这个问题有关吗?或者只是表面上。 (我问你是因为我没有足够的经验来判断。)
  • @AndrewCheong 这与您遇到的问题无关。许多标准库类型将operator += 定义为类成员。
猜你喜欢
  • 2020-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-31
相关资源
最近更新 更多