使用`std :: enable_if`失败转发包装器

问题描述 投票:0回答:2

我正在尝试创建一个转发包装函数,该函数对中的函数调用进行计时。我需要处理2类型,

  • 一个正在计时的函数不返回值,并且

  • 其他不返回

在跳过此呼叫之前和之后,可能需要执行一些操作,因此我不能只返回func(),它处理voidnon-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声明我希望的返回类型。

c++ templates c++14 sfinae function-templates
2个回答
1
投票

您有语法错误,

-> 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;

}

Demo


1
投票

@rmawatson已经指出语法错误。但是,我想提到一些改进。

由于您正在使用,因此可以通过使用std::enable_if来使用较不冗长的helper type std::enable_if_t版本来实现相同的目的>

其次,std::enable_if_t是检查类型是否为std::is_void的标准中更好(或更合适)的特征,这还将节省一些键入。使用std::is_void(也是因为void),那会短得多! variable templates


但是,如果您可以访问See here a live demo,则可以使用#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 } 在一个函数中编写两种逻辑。只为将来的@ todo

列表😉。
if constexpr
© www.soinside.com 2019 - 2024. All rights reserved.