在包含<iostream>
的情况下,旧版本的Borland C++编译器在使用std::remove的正确重载时似乎有问题。
要重现此错误,您需要一个老版本的Borland C++生成器(例如,C++生成器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 *)
我的问题是:
有没有什么优雅的/正确的方法来修复这个问题,而不是将代码分成不同的文件?
发布于 2019-04-16 09:05:15
BCB6有两个STL库-- STLPort和RogueWave。STLPort是默认值,提供RogueWave是为了向后兼容以前的BCB版本。
您的代码试图从STLPort的<algorithm>
头调用STL std::remove()
函数(它实际上是在<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函数由<cstdio>
头引入C++中的std
名称空间,STLPort的<algorithm>
头包括该头。甚至有一条关于remove()
的评论,<algorithm>
在<stl/_algo.h>
之前包含了<cstdio>
# 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
因此,STLPort在定义自己的remove()
算法之前总是包含<cstdio>
,据说是为了处理命名冲突。
但是,也就是说,您看到的所有错误都是由于编译器认为您试图调用的是单参数STL C函数,而不是3参数std::remove()
std::remove()
函数。为什么编译器会这么想,我不知道。这可能是BCB6如何解决重载的编译器错误。
然而,这个问题只影响STLPort,而不影响RogueWave,因为RogeWave的<algorithm>
头不会导致包含<cstdio>
(事实上,RogueWave甚至不像STLPort那样尝试解决C和remove()
之间的任何命名冲突)。
因此,一种解决方案是允许使用RogueWave而不是STLPort,方法是在任何STL头之前定义_USE_OLD_RW_STL
:
#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中测试了所有这些解决方案,它们都在这个场景中工作。
发布于 2019-04-15 15:33:45
有一些东西你可以尝试,但对此持保留态度,因为我没有可用的C++构建器来测试它。
using声明可以将名称从一个命名空间引入到另一个命名空间中,这可以在限定查找中使用。但是,只有在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 );
}
https://stackoverflow.com/questions/55683587
复制相似问题