조건부 운영자는 과부하 된 멤버 기능 포인터를 해결할 수 없습니다
-
07-07-2019 - |
문제
C ++에서 과부하 된 멤버 기능에 대한 포인터를 다루는 사소한 문제가 있습니다. 다음 코드는 잘 컴파일됩니다.
class Foo {
public:
float X() const;
void X(const float x);
float Y() const;
void Y(const float y);
};
void (Foo::*func)(const float) = &Foo::X;
그러나 이것은 컴파일하지 않습니다 (컴파일러는 과부하가 모호하다고 불평합니다) :
void (Foo::*func)(const float) = (someCondition ? &Foo::X : &Foo::Y);
아마도 이것은 컴파일러가 기능 포인터 유형과 별도로 조건부 연산자의 반환 값을 정렬하는 것과 관련이 있습니까? 나는 그것을 둘러 볼 수 있지만, 사양이 얼마나 직관적이지 않은 것처럼 보이기 때문에이 모든 것이 효과가 있다고 말하는지 알고 싶습니다. .
MSVC ++를 사용하고 있습니다.
감사!
해결책
섹션 13.4/1 ( "오버로드 된 함수의 주소", [Over.over]) :
인수없이 과부하 된 기능 이름을 사용하는 것은 특정 컨텍스트에서 기능, 기능에 대한 포인터 또는 과부하 세트의 특정 함수에 대한 멤버 함수에 대한 포인터를 해결합니다. 함수 템플릿 이름은 그러한 컨텍스트에서 과부하 된 함수 세트의 이름을 지정하는 것으로 간주됩니다. 선택된 함수는 유형이 컨텍스트에 필요한 대상 유형과 일치하는 기능입니다. 대상이 될 수 있습니다
- 초기화되는 객체 또는 기준 (8.5, 8.5.3),
- 과제의 왼쪽 (5.17),
- 함수의 매개 변수 (5.2.2),
- 사용자 정의 연산자 (13.5)의 매개 변수
- 함수, 연산자 함수 또는 변환 (6.6.3)의 반환 값
- 명시 적 유형 변환 (5.2.3, 5.2.9, 5.4).
과부하 함수 이름은 다음과 같이 앞에 올 수 있습니다
&
운영자. 과부하 된 기능 이름은 나열된 것 이외의 컨텍스트에서 인수없이 사용해서는 안됩니다. [의 뜻메모: 과부하 된 기능 이름을 둘러싼 중복 괄호 세트는 무시됩니다 (5.1). ]
그만큼 표적 위 목록에서 선택되기를 바랐습니다. 첫 번째 목록은 초기화되었습니다. 그러나 조건부 운영자가 있으며 조건부 운영자는 대상 유형이 아닌 피연산자에서 유형을 결정합니다.
명시 적 유형 변환이 대상 목록에 포함되므로 조건부 표현식에서 각 멤버 포인터 표현식을 별도로 유형 할 수 있습니다. 먼저 typedef를 만들 것입니다.
typedef void (Foo::* float_func)(const float);
float_func func = (someCondition ? float_func(&Foo::X) : float_func(&Foo::Y));
다른 팁
노력하다:
void (Foo::*func1)(const float) = &Foo::X;
void (Foo::*func2)(const float) = &Foo::Y;
void (Foo::*func3)(const float) = (someCondition ? func1:func2);
문제는 연산자 삼분의 결과 유형이 인수에 의해 결정된다는 것입니다.
이 상황에서는 입력 유형에 다중 옵션이 있기 때문에 결과 유형을 결정할 수 없습니다. 삼차 연산자의 유형이 과제를 시도 할 것이라고 결정되기 전까지는 아닙니다.
예시:
class Foo {
public:
void X(float x) {}
void Y(float y) {}
float X() const;
};
typedef void (Foo::*Fff)(float);
Fff func = &Foo::X;
Fff func2 = true ? (Fff)&Foo::X : (Fff)&Foo::Y;
int main(){
return 0;
}
과부하를 해결하려면 즉시 & foo :: x를 캐스트해야합니다. 오버로드 된 float x ()에 주석을 달면 그렇게 할 필요가 없습니다.
컴파일러가 3 원 표현식의 필요한 반환 유형을 유추 할만 큼 똑똑하지 않은 것처럼 보입니다 (버그 일 수 있음).