Параметр шаблона Variadic в середине списка параметров - PullRequest
0 голосов
/ 09 июня 2018

Я пытаюсь указать функцию, которая принимает обобщенную функцию в качестве параметра.Функция определяется следующим образом:

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

Как указать универсальную функцию, которая принимает эту универсальную функцию в качестве параметра?Я пробовал это:

template<typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
TRet wrap(TsArgs... args) {
  return F(args...);
}

Чтобы обернуть эту функцию:

bool foo(int x, double y) {
    return x < y;
}

Примерно так:

Fun<bool, int, double> func = wrap<bool, int, double, foo>;

Однако, к сожалению, это не компилируется.gcc 8.1 имеет следующее сообщение об ошибке:

<source>:16:35: error: no matches converting function 'wrap' to type 'Fun<bool, int, double>' {aka 'bool (*)(int, double)'}
     Fun<bool, int, double> func = wrap<bool, int, double, foo>;
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

, а clang 6 имеет следующую ошибку:

<source>:16:35: error: address of overloaded function 'wrap' does not match required type 'bool (int, double)'
    Fun<bool, int, double> func = wrap<bool, int, double, foo>;
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Однако, если я заменим TsArgs на int, double, так же, какв сигнатуре foo() он компилируется просто отлично, позволяя мне поверить, что эти аргументы шаблона переменной в середине списка параметров не работают, как я ожидал.Как я мог достичь своей цели иначе?

Вот MCVE:

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

template<typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
TRet wrap(TsArgs... args) {
    return F(args...);
}

bool foo(int x, double y) {
    return x < y;
}

int main() {
    Fun<bool, int, double> func = wrap<bool, int, double, foo>;
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

Если вы можете использовать C ++ 17, вы можете использовать auto для параметра шаблона.

Это может сильно упростить мой предыдущий ответ.

Или лучше: упростить использованиеобертка.

Если вы определите структуру wrapHelper следующим образом

template <typename T, T>
struct wrapHelper;

template <typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
struct wrapHelper<Fun<TRet, TsArgs...>, F>
 {
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

, вы можете написать wrapper, используя auto, следующим образом

template <auto X>
struct wrap : public wrapHelper<decltype(X), X>
 { };

Таким образом, нет необходимости объяснять тип возвращаемого значения (TRet) и типы аргументов (TsArgs...): они выводятся (в wrapHelper) из foo.

Итак, вместоиз

Fun<bool, int, double> func = wrap<bool, int, double>::func<foo>;

вы должны написать

Fun<bool, int, double> func = wrap<foo>::func;

или также

auto func = wrap<foo>::func;

Ниже приведен полный пример компиляции

#include <iostream>
#include <type_traits>

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

bool foo(int x, double y)
 { return x < y; }

template <typename T, T>
struct wrapHelper;

template <typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
struct wrapHelper<Fun<TRet, TsArgs...>, F>
 {
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

template <auto X>
struct wrap : public wrapHelper<decltype(X), X>
 { };

int main()
 {   
   auto func { wrap<foo>::func };

   static_assert( std::is_same<decltype(func), Fun<bool, int, double>>{} );

   std::cout << func(1, 2.0) << std::endl;
 }
0 голосов
/ 09 июня 2018

Возможно, вы можете сделать wrap в два этапа: (1) структура шаблона, которая получает параметры шаблона TRet и TArgs... и (2) статическая функция шаблона func(), которая получает параметр шаблона Fun<TRet, TsArgs...>.

Что-то вроде

template <typename TRet, typename... TsArgs>
struct wrap
 {
   template <Fun<TRet, TsArgs...> F>
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

, которое вы можете использовать таким образом

Fun<bool, int, double> func = wrap<bool, int, double>::func<foo>;

Ниже приведен полный рабочий пример

#include <iostream>

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

template <typename TRet, typename... TsArgs>
struct wrap
 {
   template <Fun<TRet, TsArgs...> F>
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

bool foo(int x, double y)
 { return x < y; }

int main()
 {
   Fun<bool, int, double> func = wrap<bool, int, double>::func<foo>;

   std::cout << func(1, 2.0) << std::endl;
 }
...