과부하 된 함수를 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 참조 .