오버로드 된 함수에 대한 포인터를 어떻게 지정합니까? . 예를 들어 class

과부하 된 함수를 std::for_each()알고리즘 에 전달하고 싶습니다 . 예를 들어

class A {
    void f(char c);
    void f(int i);

    void scan(const std::string& s) {
        std::for_each(s.begin(), s.end(), f);
    }
};

컴파일러가 f()반복자 유형 으로 해결 될 것으로 기대합니다 . 분명히 (GCC 4.1.2) 그렇게하지 않습니다. 그렇다면 f()원하는 것을 어떻게 지정할 수 있습니까?



답변

함수 포인터 유형에 의해 암시 된 함수 서명에 따라 사용할 static_cast<>()것을 지정하는 f데 사용할 수 있습니다 .

// Uses the void f(char c); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(char)>(&f));
// Uses the void f(int i); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(int)>(&f)); 

또는 다음을 수행 할 수도 있습니다.

// The compiler will figure out which f to use according to
// the function pointer declaration.
void (*fpc)(char) = &f;
std::for_each(s.begin(), s.end(), fpc); // Uses the void f(char c); overload
void (*fpi)(int) = &f;
std::for_each(s.begin(), s.end(), fpi); // Uses the void f(int i); overload

경우 f멤버 함수는, 당신은 사용이 필요 mem_fun하거나 경우에, 사용 이 박사 Dobb의 기사에서 제시 한 솔루션을 .


답변

구조에 람다! (참고 : C ++ 11 필요)

std::for_each(s.begin(), s.end(), [&](char a){ return f(a); });

또는 lambda 매개 변수에 decltype을 사용하십시오.

std::for_each(s.begin(), s.end(), [&](decltype(*s.begin()) a){ return f(a); });

다형성 람다 (C ++ 14) :

std::for_each(s.begin(), s.end(), [&](auto a){ return f(a); });

또는 과부하를 제거하여 명확하게 표현하십시오 (자유 기능에만 작동).

void f_c(char i)
{
    return f(i);
}

void scan(const std::string& s)
{
    std::for_each(s.begin(), s.end(), f_c);
}

답변

왜 안돼?

컴파일러가 f()반복자 유형 으로 해결 될 것으로 기대합니다 . 분명히 (gcc 4.1.2) 그렇게하지 않습니다.

그 경우라면 좋을 것입니다! 그러나 for_each함수 템플릿은 다음과 같이 선언됩니다.

template <class InputIterator, class UnaryFunction>
UnaryFunction for_each(InputIterator, InputIterator, UnaryFunction );

템플릿 공제 UnaryFunction는 통화 시점에 유형을 선택해야합니다 . 그러나 f특정 유형이 없습니다-과부하 된 기능이므로 f각각 다른 유형을 가진 많은 것이 있습니다. 현재 for_each템플릿 공제 프로세스를 지원할 수있는 방법은 없습니다.f 원하는 것을 템플릿 공제가 단순히 실패합니다. 템플릿 공제에 성공하려면 콜 사이트에서 더 많은 작업을 수행해야합니다.

그것을 고치는 일반적인 해결책

몇 년 동안 여기에오고 나중에 C ++ 14. 오히려 사용을보다가 static_cast(템플릿 공제하는 “고정”으로 성공할 수 있도록 것이다 f우리가 사용하고자하지만, 수동으로 “수정”올바른 일에 오버로드 확인을 수행 할 필요), 우리는 우리를 위해 컴파일러 작품을 만들고 싶어. 우리는 f일부 인수 를 요청하고 싶습니다 . 가능한 가장 일반적인 방법으로,

[&](auto&&... args) -> decltype(auto) { return f(std::forward<decltype(args)>(args)...); }

타이핑하기는 쉽지만 이런 종류의 문제는 성가신 일이 자주 발생하므로 매크로로 한 번 감싸는 것이 좋습니다.

#define AS_LAMBDA(func) [&](auto&&... args) -> decltype(func(std::forward<decltype(args)>(args)...)) { return func(std::forward<decltype(args)>(args)...); }

그런 다음 사용하십시오.

void scan(const std::string& s) {
    std::for_each(s.begin(), s.end(), AS_LAMBDA(f));
}

이것은 컴파일러가 원하는 것을 정확하게 수행합니다-이름 f자체 에 대한 과부하 해결을 수행하고 올바른 일을하십시오. 이것은 f무료 기능인지 멤버 기능 인지에 관계없이 작동 합니다.


답변

귀하의 질문에 대답하지는 않지만 내가 찾은 유일한 사람입니까

for ( int i = 0; i < s.size(); i++ ) {
   f( s[i] );
}

for_each이 경우 silico에서 제안한 대안 보다 간단하고 짧 습니까?


답변

여기서 문제는 과부하 해결이 아니라 실제로 템플릿 매개 변수 공제 인 것 같습니다 . @In silico 의 탁월한 답변 은 일반적으로 모호한 과부하 문제를 해결 std::for_each하지만 , 템플릿 매개 변수명시 적으로 지정 하는 것이 가장 좋습니다 .

// Simplified to use free functions instead of class members.

#include <algorithm>
#include <iostream>
#include <string>

void f( char c )
{
  std::cout << c << std::endl;
}

void f( int i )
{
  std::cout << i << std::endl;
}

void scan( std::string const& s )
{
  // The problem:
  //   error C2914: 'std::for_each' : cannot deduce template argument as function argument is ambiguous
  // std::for_each( s.begin(), s.end(), f );

  // Excellent solution from @In silico (see other answer):
  //   Declare a pointer of the desired type; overload resolution occurs at time of assignment
  void (*fpc)(char) = f;
  std::for_each( s.begin(), s.end(), fpc );
  void (*fpi)(int)  = f;
  std::for_each( s.begin(), s.end(), fpi );

  // Explicit specification (first attempt):
  //   Specify template parameters to std::for_each
  std::for_each< std::string::const_iterator, void(*)(char) >( s.begin(), s.end(), f );
  std::for_each< std::string::const_iterator, void(*)(int)  >( s.begin(), s.end(), f );

  // Explicit specification (improved):
  //   Let the first template parameter be derived; specify only the function type
  std::for_each< decltype( s.begin() ), void(*)(char) >( s.begin(), s.end(), f );
  std::for_each< decltype( s.begin() ), void(*)(int)  >( s.begin(), s.end(), f );
}

void main()
{
  scan( "Test" );
}

답변

C ++ 11을 사용하는 것이 마음에 들지 않으면 정적 캐스트와 비슷하지만 추한 것보다 덜 영리한 도우미가 있습니다.

template<class... Args, class T, class R>
auto resolve(R (T::*m)(Args...)) -> decltype(m)
{ return m; }

template<class T, class R>
auto resolve(R (T::*m)(void)) -> decltype(m)
{ return m; }

(멤버 함수를 위해 작동합니다. 독립형 함수를 위해 작동하도록 수정하는 방법이 분명 해야합니다. 두 버전을 모두 제공 할 수 있어야하고, 컴파일러가 당신에게 맞는 하나를 선택합니다.)

제안 해 주신 Miro Knejp에게 감사드립니다 : https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J 참조 .