Есть ли способ в C ++ ссылаться на шаблон функции, не вызывая его и не предоставляя его параметры шаблона? - PullRequest
0 голосов
/ 06 октября 2018

Вот код, который я хотел бы работать:

template <class T> void Foo(T&& param);

template <class F> void CallMe(F&& func)
{
    func(42);
}

int main()
{
    CallMe(Foo);
}

Компилятор задыхается, когда пытается создать экземпляр CallMe, потому что не знает, что я имею в виду под Foo.Это работает, если я напишу Foo<int>, конечно, но я бы хотел этого избежать, потому что в реальном коде параметры шаблона могут быть сложными.

Мой текущий обходной путь - использовать вызываемые объекты вместо свободных функций.Например:

class Foo
{
  public:
    template <class T> void operator()(T&&);
};

Это прекрасно работает, но я уверен, что это запутает пользователей моей библиотеки.Могу ли я использовать шаблонную магию, чтобы первая версия работала?

Ответы [ 4 ]

0 голосов
/ 08 октября 2018
#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

#define OVERLOADS_OF(...) \
  [](auto&&...args) \
  RETURNS( __VA_ARGS__( decltype(args)(args)... ) )

затем

CallMe(OVERLOADS_OF(Foo));

создает объект функции, который представляет перегрузки имени Foo, которые включают в себя функции, создаваемые функцией шаблона с именем Foo.

RETURNS также полезно в других контекстах. @ У Барри есть предложение сделать RETURNS(X) похожим на => X, по крайней мере, для лямбд.

0 голосов
/ 06 октября 2018

Можно сделать что-то похожее на код в вопросе, но не совсем.

Вызов функции:

int main()
{
    CallMe(Foo);
}

ожидает объект в качестве параметра.Объект может быть указателем на функцию, экземпляром класса, лямбда-выражением или чем-то подобным.Это не может быть необоснованная функция шаблона, так как это не объект.Только экземплярная функция является объектом.

Как говорится в исходном вопросе, использование объектов, подобных функциям, является обходным решением и предполагает, что для некоторых пользователей следующее слишком запутанно:

class Foo
{
  public:
    template <class T> void operator()(T&&);
};

Вместо этого можно использовать общую лямбду, которая в основном такая же, но без всей плиты котла.Общая лямбда выглядит почти как обычная функция:

auto Foo = [](auto x) 
{ 
   std::cout << x << '\n';
};
int main()
{
   CallMe(Foo);
}
0 голосов
/ 06 октября 2018

Есть ли какая-то магия шаблонов, которую я могу использовать, чтобы заставить работать первую версию?

Я хочу.И я надеюсь, что когда-нибудь.В этой области было несколько предложений (например, P0119 и P0834 ).До этого момента лучшее, что вы можете сделать, - написать макрос для преобразования вашего имени в объект функции, который вызывает это имя:

#define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
#define LIFT(name) [&](auto&&... args)     \
    noexcept(noexcept(name(FWD(args)...))) \
    -> decltype(name(FWD(args)...))        \
    { return name(FWD(args)...); }

Это позволяет вам написать:

CallMe(LIFT(Foo));

, который в противном случае делает то, что вы хотите.

0 голосов
/ 06 октября 2018

Есть ли какое-то волшебство шаблона, которое я могу использовать, чтобы заставить работать первую версию?

Нет.

Имя шаблона функции не называет функциютипа но семья из них.Если бы это было возможно, и тип func был бы выведен из Foo, тип T останется не выведенным, что необходимо для создания экземпляра Foo.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...