передача лямбды в void указанный шаблон не удалась - PullRequest
0 голосов
/ 03 декабря 2018

Я упростил задачу настолько, насколько мог, поэтому вот эта функция:

class Test
{
public:
    template<class T>
    void ExecuteFunction(std::function<void(T)> f)
    {
    }
};

, если я вызываю функцию с помощью int-typing, все работает нормально, однако, если я вызываю ее с помощьюлямбда с пустым типом больше не компилируется.

Test test;

test.ExecuteFunction<void>(    // doesn't compile
    [](void)->void
{
    int i = 5;
});

test.ExecuteFunction<int>(    // this compiles
    [](int)->void
{
    int i = 5;
});

Ошибки компиляции:

Error   C2672   'Test::ExecuteFunction': no matching overloaded function found  
Error   C2770   invalid explicit template argument(s) for 'void Test::ExecuteFunction(std::function<void(P)>)'  
Error (active)      no instance of function template "Test::ExecuteFunction" matches the argument list

есть ли способ обойти это?как кто-то может указать шаблон, чтобы оба вызова работали?

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

Вы можете добавить перегрузку к классу следующим образом:

// as before:
template<class T>
void ExecuteFunction(std::function<void(T)> f) {}

// new overload (not a template):
void ExecuteFunction(std::function<void()> f) {}

Поскольку вы не можете использовать вывод типов, вы можете явно вызывать эту функцию, не задавая параметр шаблона следующим образом.

Test test;

test.ExecuteFunction(
     [](void)->void
     {
     int i = 5;
     });
0 голосов
/ 03 декабря 2018

Слишком поздно играть?

Я предлагаю другое решение, основанное на характеристике нестандартного типа (со специализацией для void), которое, учитывая тип T, определяет правильное std::function type;я имею в виду

template <typename T>
struct getFuncType
 { using type = std::function<void(T)>; };

template <>
struct getFuncType<void>
 { using type = std::function<void()>; };

Таким образом, ваш ExecuteFunction() просто станет

template <typename T>
void ExecuteFunction (typename getFuncType<T>::type f)
{
}

Если вы хотите немного упростить использование getFuncType, вы можете добавить помощника using кизвлеките type

template <typename T>
using getFuncType_t = typename getFuncType<T>::type;

, чтобы ExecuteFunction() можно было упростить следующим образом

template <typename T>
void ExecuteFunction (getFuncType_t<T> f)
{
}
0 голосов
/ 03 декабря 2018

Конечно, void в скобках - это всего лишь винтажный сахар в стиле C.Вы должны будете специализировать свой шаблон:

template<> void Test::ExecuteFunction<void>(std::function<void()> f) {}

Если это не компилируется, хорошо, вы можете использовать вспомогательный шаблон для инкапсуляции выбора типа:

#include <iostream>
#include <functional>

template<class T> struct callable {
    using type = std::function<void(T)>;
};
template<class T> using callable_t =
    typename callable<T>::type;
template<> struct callable<void> {
    using type = std::function<void()>;
};

class Test
{
public:
    template<class T>
    void ExecuteFunction(callable_t<T> f) {}
};

int main() {
    Test test;

    test.ExecuteFunction<void>(    // does compile
                    [](void)->void {});

    test.ExecuteFunction<int>(    // this compiles
                    [](int)->void {});
}

Но будьтепомните, что таким образом вам придется также что-то делать с передачей аргументов (в вашем примере аргумент общего случая является унарным, но специализация для void ожидает объект нулевой функции).

...