Что касается этого вопроса, который, возможно, слишком упрощен, я приведу здесь более сложный пример. Проблема, на которую я претендую, изображена следующим кодом:
// test3.cpp
using namespace std;
template<typename T>
struct exer
{
template<typename R, typename... rArgs, typename... pArgs>
R operator()(R(T::*f)(rArgs...), pArgs&&... args)
{
return (t.*f)(forward<pArgs>(args)...);
}
T t;
};
struct A
{
int addition() { return 0; }
template<typename... Args>
int addition(int a, Args... args) { return a + addition(args...); }
};
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
return m_e(&A::addition, forward<Args>(args)...);
}
private:
exer<A> m_e;
};
int main()
{
B b;
cout << b.addition(1, 2, 3, 4) << endl;
}
Проблема здесь в том, что при создании B::addition
тип &A::addition
неизвестен, поскольку существуют разные перегрузки. Более того, B::addition
также не знает, какую перегрузку нужно использовать. Это не знает компилятор, пока функция не будет вызвана. Но для того, чтобы правильно указать, какая перегрузка должна использоваться в exer<A>::operator()
, мне нужно выполнить приведение &A::addition
, чтобы привести его к правильной перегрузке.
Как мне извлечь тип правильной перегрузки целевой функции?
1 ответ
Измените вопрос. Если вы можете заставить exer
принимать вызываемый объект вместо указателя на функцию-член, например:
template<typename T>
struct exer
{
T t;
template<typename F, typename... pArgs>
auto operator()(F f, pArgs&&... args)
-> decltype(f(t, forward<pArgs>(args)...))
{
return f(t, forward<pArgs>(args)...);
}
};
Тогда вы можете сделать это вместо этого:
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
struct Invoker {
auto operator()(A& a, Args&&... args) const
->decltype(a.addition(std::forward<Args>(args)...))
{ return a.addition(std::forward<Args>(args)...); }
};
return m_e(Invoker(), forward<Args>(args)...);
}
private:
exer<A> m_e;
};
Теперь выбор правильного A::addition
выполняется компилятором с использованием обычных правил разрешения перегрузки.
Вместо Invoker
вы можете использовать лямбда-выражение, которое уменьшает количество повторений:
return m_e( [](A& a, Args&&... as) {
return a.addition(forward<Args>(as)...);
},
forward<Args>(args)...);
Похожие вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .