C ++ VS2008 - 类模板实例化的奇怪错误

时间:2014-09-03 13:07:48

标签: c++ templates visual-studio-2008

我正在将一个相对较大的代码从Linux移植到Windows(Visual Studio 2008,我必须使用它)。 我完成了移植和它的工作,但我不得不评论一小段代码,因为Visual Studio给出了错误,我无法理解为什么。 所以,基本上,有一个仿函数从std :: map中收集所有"项目"满足某种条件,以下列方式定义:

/*
 * Map collector
 */
template<class TMap>
class CMapCollector
{
    public:
        typedef typename TMap::value_type tValueType;

        CMapCollector(void)
        { }

        void operator () (const tValueType& rcValue)
        {
            if (CheckCondition(rcValue))
                mCollector.push(rcValue);
        }

        bool NextResult(void) const
        {
            return (!mCollector.empty());
        }

        tValueType GetResult(void)
        {
            if (!NextResult())
                return tValueType();

            tValueType curr_value = mCollector.front();
            mCollector.pop();
            return curr_value;
        }

    private:
        virtual bool CheckCondition(const tValueType& rcValue) const = 0;

        typedef std::queue<tValueType> tCollectorContainer;

        tCollectorContainer mCollector;
};

然后,通过继承它,定义了一些收集器类。 我写了一个显示错误的小例子,以便从所有其他代码中提取它:

/*
 * Some class
 */
class CMyClass
{
    public:
        CMyClass(const int cNum) : mNum(cNum)
        { }

        bool DifferentFrom(const int cFrom) const
        {
            return (Get() != cFrom);
        }

        bool EqualTo(const int cTo) const
        {
            return (Get() == cTo);
        }

    private:
        int Get(void) const
        {
            return mNum;
        }

        int mNum;
};

/* Some map definition */
typedef std::map<int, CMyClass *> tMyMap;

/*
 * Real collectors
 */

class CNoNullCollector : public CMapCollector<tMyMap>
{
    private:
        bool CheckCondition(const tValueType& rcValue) const
        {
            return (rcValue.second->DifferentFrom(0));
        }
};

class CValueCollector : public CMapCollector<tMyMap>
{
    public:
        CValueCollector(const int cValue) : mValue(cValue)
        { }

    private:
        bool CheckCondition(const tValueType& rcValue) const
        {
            return (rcValue.second->EqualTo(mValue));
        }

        int mValue;
};

/*
 * main
 */
int main(int argc, char *argv[])
{
    tMyMap my_map;

    /* Insert some value */
    my_map.insert(std::make_pair(1, new CMyClass(0)));
    my_map.insert(std::make_pair(2, new CMyClass(1)));
    my_map.insert(std::make_pair(3, new CMyClass(2)));
    my_map.insert(std::make_pair(4, new CMyClass(2)));
    my_map.insert(std::make_pair(5, new CMyClass(3)));

    /* Collect values */
    CNoNullCollector collector = std::for_each(my_map.begin(), my_map.end(), CNoNullCollector());
    while (collector.NextResult())
    {
        CNoNullCollector::tValueType curr_result = collector.GetResult();
        /* Do something ... */
    }

    /* Free memory, not written ... */

    return 0;
}

这个代码在Linux上使用g ++编译得很好(我尝试使用g ++ 4.2和4.9,在机器上可用)。 我也试过Visual Studio 2013,它很好。 但是,使用VS2008(以及VS2010)进行编译时,它会在实例化类模板&#34; CMapCollector&#34;时出错。 错误发生在std :: swap函数中,此时从std :: pair调用(&#34;实用程序&#34;文件,标准包含):

template<class _Ty> inline
void swap(_Ty& _Left, _Ty& _Right)
{   // exchange values stored at _Left and _Right
if (&_Left != &_Right)
    {   // different, worth swapping
    _Ty _Tmp = _Left;

    _Left = _Right;     // <-- error C3892: '_Left' : you cannot assign to a variable that is const
    _Right = _Tmp;      // <-- error C3892: '_Right' : you cannot assign to a variable that is const
    }
}

这是完整的错误消息:

    c:\program files (x86)\microsoft visual studio 9.0\vc\include\utility(22) : error C3892: '_Left' : you cannot assign to a variable that is const
        c:\program files (x86)\microsoft visual studio 9.0\vc\include\utility(31) : see reference to function template instantiation 'void std::swap<_Ty>(_Ty &,_Ty &)' being compiled
        with
        [
            _Ty=int
        ]
        c:\program files (x86)\microsoft visual studio 9.0\vc\include\utility(64) : see reference to function template instantiation 'void std::_Swap_adl<_Ty1>(_Ty &,_Ty &)' being compiled
        with
        [
            _Ty1=int,
            _Ty=int
        ]
        c:\program files (x86)\microsoft visual studio 9.0\vc\include\utility(61) : while compiling class template member function 'void std::pair<_Ty1,_Ty2>::swap(std::pair<_Ty1,_Ty2> &)'
        with
        [
            _Ty1=const int,
            _Ty2=CMyClass *
        ]
        c:\program files (x86)\microsoft visual studio 9.0\vc\include\deque(518) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
        with
        [
            _Ty1=const int,
            _Ty2=CMyClass *
        ]
        c:\program files (x86)\microsoft visual studio 9.0\vc\include\queue(24) : see reference to class template instantiation 'std::deque<_Ty>' being compiled
        with
        [
            _Ty=std::pair<const int,CMyClass *>
        ]
        c:\users\my_name\desktop\test\test\test.cpp(42) : see reference to class template instantiation 'std::queue<_Ty>' being compiled
        with
        [
            _Ty=std::pair<const int,CMyClass *>
        ]
        c:\users\my_name\desktop\test\test\test.cpp(81) : see reference to class template instantiation 'CMapCollector<TMap>' being compiled
        with
        [
            TMap=tMyMap
        ]
c:\program files (x86)\microsoft visual studio 9.0\vc\include\utility(23) : error C3892: '_Right' : you cannot assign to a variable that is const

如果我评论实例化类模板的部分:

CNoNullCollector collector = std::for_each(my_map.begin(), my_map.end(), CNoNullCollector());
while (collector.NextResult())
{
    CNoNullCollector::tValueType curr_result = collector.GetResult();
    /* Do something ... */
}

编译将成功完成。 我知道恒定性有一些问题,但我不明白在哪里。为什么g ++成功编译它?

编辑:

我明白这是与std :: queue和&#34; key&#34;相关的东西。根据定义,std :: map(以及std :: pair的&#34; first&#34;)是不变的,但是我没有弄清楚如何解决它

1 个答案:

答案 0 :(得分:0)

我最后通过使用常量指针队列来解决,所以我只是将指针存储到std :: pair而不是std :: pair本身的值,这也更有意义:

std::queue<const tValueType *>

因此最终的地图收集器类变为:

/*
 * Map collector
 */
template<class TMap>
class CMapCollector
{
    public:
        typedef typename TMap::value_type tValueType;

        CMapCollector(void)
        { }

        void operator () (const tValueType& rcValue)
        {
            if (CheckCondition(rcValue))
                mCollector.push(&rcValue);
        }

        bool NextResult(void) const
        {
            return (!mCollector.empty());
        }

        const tValueType *GetResult(void)
        {
            if (!NextResult())
                return NULL;

            const tValueType *curr_value = mCollector.front();
            mCollector.pop();
            return curr_value;
        }

    private:
        virtual bool CheckCondition(const tValueType& rcValue) const = 0;

        typedef std::queue<const tValueType *> tCollectorContainer;

        tCollectorContainer mCollector;
};

这也适用于VS2008