向量/算法与iostream之间的不兼容

时间:2019-04-15 06:28:40

标签: c++ c++builder-6

当包含<iostream>时,使用正确的std :: remove重载,Borland C ++编译器的较旧版本似乎存在问题。

要重现此错误,您需要使用Borland C ++ Builder的较旧版本(例如C ++ Builder 6)和以下非常小的代码段:

#include <vector>
#include <algorithm>

void __fastcall TFormMain::Button1Click(TObject *Sender)
{
    std::vector< int > Selection;
    std::remove( Selection.begin(), Selection.end(), 10 );
}

(我知道:此代码不执行任何操作,但至少可以编译...)

一切正常,直到您在代码中的某些地方包含iostream:

#include <vector>
#include <iostream>
#include <algorithm>

void __fastcall TFormMain::Button1Click(TObject *Sender)
{
    std::vector< int > Selection;
    std::remove( Selection.begin(), Selection.end(), 10 );
}

这将导致一些编译器错误:

[C++ Fehler] UnitFormMain.cpp(22): E2034 Konvertierung von 'int *' nach 'const char *' nicht möglich
[C++ Fehler] UnitFormMain.cpp(22): E2342 Keine Übereinstimmung des Typs beim Parameter '__path' ('const char *' erwartet, 'int *' erhalten)
[C++ Fehler] UnitFormMain.cpp(22): E2227 Zu viele Parameter im Aufruf von std::remove(const char *)

英语:

[C++ Error] UnitFormMain.cpp(22): E2034 Cannot convert 'int *' to 'const char *'
[C++ Error] UnitFormMain.cpp(22): E2342 Type mismatch in parameter '__path' (wanted 'const char *', got 'int *')
[C++ Error] UnitFormMain.cpp(22): E2227 Extra parameter in call to std::remove(const char *)

我的问题是:

是否有任何优雅/正确的方法来解决此问题,而无需将代码分成不同的文件?

2 个答案:

答案 0 :(得分:3)

您可以尝试一些方法,但是要花点时间,因为我没有C ++生成器来测试。

使用声明可以将名称从一个名称空间引入另一个名称空间,可以在限定的查找中使用它。但是,仅引入在using声明时可见的重载。因此,如果我们仅捕获我们想要的重载,并在新的名称空间上进行合格的名称查找,那么就不会有歧义。在代码中:

#include <vector>
#include <algorithm>

namespace resolve_std {
    using std::remove;
}

#include <iostream>

void __fastcall TFormMain::Button1Click(TObject *Sender)
{
    std::vector< int > Selection;
    // Should only use the overloads introduced prior to including <iostream>
    resolve_std::remove( Selection.begin(), Selection.end(), 10 );
}

答案 1 :(得分:3)

BCB6具有两个STL库-STLPort和RogueWave。 STLPort是默认设置,RogueWave是为了与以前的BCB版本向后兼容而提供的。

您的代码正在尝试从STLPort的std::remove()标头(实际上是在<algorithm>中定义)调用STL <stl/_algo.h>函数:

template <class _ForwardIter, class _Tp>
_STLP_INLINE_LOOP _ForwardIter 
remove(_ForwardIter __first, _ForwardIter __last, const _Tp& __value)

但是,C运行时库在<stdio.h>标头中具有自己的单参数remove()函数:

int       _RTLENTRY _EXPFUNC remove(const char * __path);

此C函数通过std头引入C ++中的<cstdio>命名空间中,STLPort的<algorithm>头包含在其中。在remove()<algorithm>之前包括<cstdio>的地方,甚至有关于<stl/_algo.h>的评论:

# if ! defined (_STLP_USE_NAMESPACES)
// remove() conflicts, <cstdio> should always go first
#  include <cstdio>
# endif

# ifndef _STLP_INTERNAL_ALGO_H
#  include <stl/_algo.h>
# endif

甚至_algo.h也有类似的评论:

# ifdef __SUNPRO_CC
// remove() conflict
#  include <cstdio>
# endif

因此,在定义自己的<cstdio>算法之前,STLPort总是包含remove(),应该是 来处理命名冲突。

但是,话虽这么说,您看到的所有错误都是由于编译器认为您试图调用1参数std::remove() C函数而不是3参数std::remove() STL而引起的。功能。我不知道为什么编译器会这样认为。可能是BCB6如何解决重载的编译器错误。

但是,该问题仅影响STLPort,而不影响RogueWave,因为RogeWave的<algorithm>标头不会导致包含<cstdio>(实际上,RogueWave甚至不尝试解决与C和STL之间的remove(),就像STLPort一样。

因此,一种解决方案是通过在任何STL标头之前定义_USE_OLD_RW_STL来启用RogueWave而不是STLPort:

#define _USE_OLD_RW_STL
// alternatively, add `_USE_OLD_RW_STL` to the Conditionals
// list in the Project Options...

#include <vector>
#include <iostream>
#include <algorithm>

...

std::vector< int > Selection;
std::remove( Selection.begin(), Selection.end(), 10 ); // WORKS

否则,如果要使用STLPort,可以使用Kamil Cuk在评论中提到的建议:

#include <vector>

#define remove _mask_remove
#include <iostream>
#undef remove

#include <algorithm>

...

std::vector< int > Selection;
std::remove( Selection.begin(), Selection.end(), 10 ); // WORKS

或者,使用answer proposed by StoryTeller

#include <vector>
#include <algorithm>

namespace resolve_std {
    using std::remove;
}

#include <iostream>

...

std::vector< int > Selection;
resolve_std::remove( Selection.begin(), Selection.end(), 10 ); // WORKS

我已经在BCB6中测试了所有这些解决方案,它们都可以在这种情况下工作。