Переадресация оболочки с использованием `std :: enable_if` завершилась неудачно - PullRequest
2 голосов
/ 03 ноября 2019

Я пытаюсь создать функцию-оболочку для пересылки, которая время вызова функции в . Есть 2 типы, с которыми мне нужно иметь дело,

  • один - это синхронизация функции, которая не возвращает значение, и

  • другие не возвращают

Могут быть операции, которые мне нужно сделать до и после вызова, который я здесь пропускаю, поэтому я не могу просто вернуть func(), который касается обоих *Типы 1017 * и non-void.

Вот оболочка для функции void.

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args) -> typename enable_if<is_same<decltype(func(args...)), void>::value>::type
{
    std::cout << "timing void function" << std::endl;
    std::forward<T>(func)(std::forward<U>(args)...);
    std::cout << "timing over" << std::endl;
}

Упаковщик для функции non-void

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args) -> typename enable_if < !is_same<decltype(func(args...)), void), decltype(func(args...)) > ::value > ::type
{
    std::cout << "timing returning function" << std::endl;
    auto val = std::forward<T>(func)(std::forward<U>(args)...);
    std::cout << "timing over" << std::endl;
    return val;
}

int main()
{
    time_function(foo, 2);
    int i = time_function(&foo_return, 1); //this generates an error
    //std::cout<<i<<std::endl;
}

foo - это функция, которая возвращает void, а foo_return возвращает целое число. Генерируемая ошибка:

<source > :28 : 129 : error : template argument 1 is invalid
auto time_function(T && func, U && ...args) -> typename enable_if<!is_same<decltype(func(args...)), void>, decltype(func(args...))>::value > ::type
^
<source>:28 : 55 : error : expected nested - name - specifier before 'enable_if'
auto time_function(T && func, U && ...args) -> typename enable_if<!is_same<decltype(func(args...)), void>, decltype(func(args...))>::value > ::type
^ ~~~~~~~~
<source>:28 : 129 : error : template argument 1 is invalid
auto time_function(T && func, U && ...args) -> typename enable_if<!is_same<decltype(func(args...)), void>, decltype(func(args...))>::value > ::type
^
<source>:28 : 129 : error : template argument 1 is invalid
<source> : 28 : 129 : error : template argument 1 is invalid
<source> : 28 : 55 : error : expected initializer before 'enable_if'
auto time_function(T && func, U && ...args) -> typename enable_if<!is_same<decltype(func(args...)), void>, decltype(func(args...))>::value > ::type
^ ~~~~~~~~

<source>: In function 'int main()' :
    <source> : 42 : 41 : error : no matching function for call to 'time_function(int (*)(int), int)'
    int i = time_function(&foo_return, 1); //error -
^
<source>:20 : 6 : note : candidate : template<class T, class ... U> typename std::enable_if<std::is_same<decltype (func(time_function::args ...)), void>::value>::type time_function(T&&, U && ...)
auto time_function(T && func, U && ...args) -> typename enable_if<is_same<decltype(func(args...)), void>::value>::type
^ ~~~~~~~~~~~~
<source> : 20 : 6 : note : template argument deduction / substitution failed :
<source> : In substitution of 'template<class T, class ... U> typename std::enable_if<std::is_same<decltype (func(time_function::args ...)), void>::value>::type time_function(T&&, U&& ...) [with T = int (*)(int); U = {int}]' :
    <source> : 42 : 41 : required from here
    <source> : 20 : 6 : error : no type named 'type' in 'struct std::enable_if<false, void>'

Насколько мне известно, оболочка верна, что не так? Я проверяю, является ли возвращаемый тип функции void, используя is_same, и если да, объявляю желаемый тип возврата, используя enable_if.

Ответы [ 2 ]

2 голосов
/ 03 ноября 2019

@ rmawatson уже указал синтаксическую ошибку. Однако я хотел бы упомянуть пару улучшений.

Поскольку вы используете , вы можете добиться того же, используя менее подробную версию std::enable_if, с помощьюиспользование вспомогательного типа std::enable_if_t

Во-вторых, std::is_void является лучшей (или подходящей) характеристикой из стандарта для проверки, является ли тип void, что также позволит сэкономить при наборе текста. Используя шаблоны переменных (также начиная с ), это было бы намного короче! ( Смотрите здесь живую демонстрацию )

#include <iostream>
#include <type_traits> // std::enable_if_t, std::is_void
// variable templates
template<class T> constexpr bool is_void_v = std::is_void<T>::value;

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args) -> std::enable_if_t<::is_void_v<decltype(func(args...))>>
{
    // ... code here
}

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args)
-> std::enable_if_t<!::is_void_v<decltype(func(args...))>, decltype(func(args...))>
{
    // ... code here
}

Однако, если у вас есть доступ к , выможно просто написать обе логики в одной функции, используя if constexpr. Только для будущего @ todo list?. ( Смотрите в прямом эфире здесь )

#include <type_traits> // std::enable_if_t, std::is_void_v

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args)
{
    if constexpr (std::is_void_v<decltype(func(args...))>)
    {
        // ... timing void function"
    } 
    else
    {
        // ... timing returning function
    }
}
1 голос
/ 03 ноября 2019

У вас есть синтаксическая ошибка,

-> typename enable_if<!is_same<decltype(func(args...)), void),decltype(func(args...))>::value>::type

-> typename enable_if<!is_same<decltype(func(args...)), void>::value, decltype(func(args...))>::type

#include <type_traits>
#include <iostream>
using namespace std;

template<typename T, typename ...U>
 auto time_function(T&& func, U&& ...args) 
    -> typename enable_if<is_same<decltype(func(args...)), void>::value>::type
{
    std::cout<<"timing void function"<<std::endl;
    std::forward<T>(func)(std::forward<U>(args)...);

    std::cout<<"timing over"<<std::endl;
}

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args)
 -> typename enable_if<!is_same<decltype(func(args...)), void>::value, decltype(func(args...))>::type
{
    std::cout<<"timing returning function"<<std::endl;
    auto val = std::forward<T>(func)(std::forward<U>(args)...);

    std::cout<<"timing over"<<std::endl;

    return val;
}


void foo(int){}
int foo_return(int){return 0;}

int main()
{

    time_function(foo, 2);
    int i = time_function(&foo_return, 1); //this generates an error
    std::cout<<i<<std::endl;

}

Демо

...