STD :: 문자열로의 자동 유형 변환 간의 C ++ 차이*
-
22-07-2019 - |
문제
학습 운동으로서, 나는 자동 유형 변환이 C ++에서 어떻게 작동하는지 살펴보고 있습니다. 나 알다 이러한 자동 유형 변환은 일반적으로 피해야하지만, 어쨌든 작동 방식을 이해함으로써 C ++에 대한 지식을 높이고 싶습니다.
나는 a StdStringConverter
자동으로 변환 할 수있는 클래스 std::string
, 그러나 컴파일러 (Debian의 G ++ 4.3.4)는 객체를 실제와 비교할 때 변환을 수행하지 않는 것 같습니다. std::string
(임시 대상의 참조와 불필요한 생성의 부족을 무시하십시오) :
#include <string>
class StdStringConverter
{
public:
explicit StdStringConverter(std::string name) : m_name(name) {}
operator const std::string () const { return m_name; }
private:
std::string m_name;
};
int main()
{
StdStringConverter converter(std::string("Me"));
const std::string name = "Me";
// Next line causes compiler error:
// no match for 'operator==' in 'converter == name'
return (converter == name) ? 0 : 1;
}
반면에, 내가 그것을 약간 바꾸면 CStringConverter
클래스, 자동 변환 하다 비교하더라도 발생합니다 char
포인터는 아마도 내가 의도 한 것이 아닐 것입니다.
#include <string>
class CStringConverter
{
public:
explicit CStringConverter(std::string name) : m_name(name) {}
operator const char* () const { return m_name.c_str(); }
private:
std::string m_name;
};
int main()
{
CStringConverter converter(std::string("Me"));
const char* name = "Me";
// Next line compiles fine, but they are not equal because the
// pointers don't match.
return (converter == name) ? 0 : 1;
}
a의 차이점에 특별한 것이 있습니까? std::string
그리고 a char*
이러한 맥락에서 컴파일러가 동일하게 취급하지 않게 하는가?
해결책
문제는 std :: string이 실제로 클래스 템플릿 std :: basic_string의 인스턴스라는 사실 때문입니다. 네임 스페이스에서 사용할 수있는 연산자 == STD는 2 개의 std :: basic_string 템플릿을 사용합니다.
template<class charT, class traits, class Allocator>
bool operator==(const basic_string& lhs,
const basic_string& rhs);
이 버전의 Operator ==가 STD :: String에서 특별히 과부하 된 경우 코드가 정상입니다. 그러나 컴파일러가 std :: basic_string의 템플릿 매개 변수에서 템플릿 인수 공제를 수행 해야하는 경우는 그렇지 않습니다. 따라서 변환 연산자의 반환이 가능하다는 것을 이해할 수 있습니다.
그러나 컴파일러는 그렇게하지 않습니다. 표준의 어느 부분이 정확하게 나타나는지 모르겠습니다. 그러나 일반적인 아이디어는 그러한 전환이 비 테일 플레이트 유형에만 효과가 있다는 것입니다.
내가 제안 할 수있는 한 가지는 당신이 네임 스페이스에 stdstringConverter를 배치하고 해당 네임 스페이스의 std :: string에 연산자 == 버전을 제공하는 것입니다. 이런 식으로 컴파일러가 해당 ADL (인수 종속 조회)과 같은 표현식을 찾으면 모든 것이 잘 작동합니다.
#include <string>
namespace n1 {
class StdStringConverter
{
public:
explicit StdStringConverter(std::string name) : m_name(name) {}
operator std::string () { return m_name; }
private:
std::string m_name;
};
bool operator==(std::string const& a, std::string const& b)
{
return a == b; //EDIT: See Paul's comment on std::operator== here.
}
}
int main()
{
using namespace n1;
StdStringConverter converter(std::string("Me"));
std::string name = "Me";
return (converter == name) ? 0 : 1;
}
다른 팁
첫 번째 예에서 두 비교 클래스 (String 및 StdstringConverter)는 유형 변환을 위해 컴파일러로부터 특별한 처리를 얻지 못합니다. 즉, 당신이 만든 운영자 과부하가 트리거되지 않음을 의미합니다. 컴파일러는 Operator == Overloads의 목록을 검토하고 그중 중 비는 stdstringconverter를 사용하여 소리를 지르기 위해 소리칩니다.
두 번째 예에서 이름은 char *입니다. 원시 유형이므로 컴파일러는 비 원시를 숯으로 변환하려고 시도합니다. 재정의가 있으므로 작동하고 주소를 비교합니다.
컴파일러는 원시 유형을 포함하지 않는 작업에서 주조를 명시하지 않습니다. 그것이 할 일은 생성자를 사용하여 유형을 일치 시키려고 시도하는 것입니다. 예를 들어 첫 번째 예제를 변경하면 다음과 같습니다.
#include <string>
class StdStringConverter
{
public:
StdStringConverter(std::string name) : m_name(name) {}
bool operator==(const StdStringConverter &name) { return m_name == name.m_name; }
operator const std::string () const { return m_name; }
private:
std::string m_name;
};
int main()
{
StdStringConverter converter(std::string("Me"));
const std::string name = "Me";
// Next line causes compiler error:
// no match for 'operator==' in 'converter == name'
return (converter == name) ? 0 : 1;
}
이제 프로그램은 0을 반환합니다. 생성자는 이제 명시 적이지 않기 때문에 컴파일러는 문자열을 stdstringconverter로 변환하기 위해이를 사용하려고 시도합니다. 이제 stdstringconverter에 연산자 ==가 있으므로 모든 것이 작동합니다.
여러 가지 요인이 있습니다. 따라서 반환 명령문을 변경하면
return (std :: operator == (이름, 이름))? 0 : 1;
분명히 같은 일을하지는 않지만 컴파일합니다. 반면에
return (std :: Operator == (변환기, 이름))? 0 : 1;
더 흥미로운 오류 메시지를 제공하지는 않습니다
'Operator == (stdstringconverter &, const std :: string &)에 대한 호출 기능 없음
연산자 ==가 Basic_string <>에서 템플릿으로 부팅 할 템플릿 매개 변수가있는 것을 상기시켜줍니다. std :: string 대신 예제에서 int를 사용하는 경우 컴파일러는 불평하지 않습니다.
std :: 문자열로 원하는 효과를 얻는 방법은 더 흥미 롭습니다 ...