Я пытаюсь предоставить оболочку вокруг std::invoke
, чтобы выполнить работу по определению типа функции, даже если функция перегружена.
(вчера я задал связанный вопрос для variadi c и версия указателя метода).
Когда функция имеет один аргумент, этот код (C ++ 17) работает как обычно при нормальных условиях перегрузки:
#include <functional>
template <typename ReturnType, typename ... Args>
using FunctionType = ReturnType (*)(Args...);
template <typename S, typename T>
auto Invoke (FunctionType<S, T> func, T arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, T&> func, T & arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, const T&> func, const T & arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, T&&> func, T && arg)
{
return std::invoke(func, std::move(arg));
}
Уменьшение раздувания кода очевидно, требуется больше входных аргументов, но это отдельная проблема.
Если у пользователя есть перегрузки, отличающиеся только константой / ссылками, вот так:
#include <iostream>
void Foo (int &)
{
std::cout << "(int &)" << std::endl;
}
void Foo (const int &)
{
std::cout << "(const int &)" << std::endl;
}
void Foo (int &&)
{
std::cout << "(int &&)" << std::endl;
}
int main()
{
int num;
Foo(num);
Invoke(&Foo, num);
std::cout << std::endl;
Foo(0);
Invoke(&Foo, 0);
}
Тогда Invoke
выводит работает неправильно, с выводом g ++:
(int &)
(const int &)
(int &&)
(const int &)
и лязг ++:
(int &)
(const int &)
(int &&)
(int &&)
(Спасибо geza за указание на то, что выходные данные clang были другими).
Так что Invoke
имеет неопределенное поведение.
I подозреваю, что метапрограммирование будет способом решения этой проблемы. Независимо от того, возможно ли правильно обработать вывод типа на сайте Invoke
?