使用 std::enable_if 转发包装器失败
Forwarding wrapper using `std::enable_if` failing
我正在尝试创建一个转发包装函数,该函数对 c++14 中的函数调用进行计时。我需要处理 2
种类型,
一个是为没有 return 值的函数计时,
其他不returning
我在这里跳过的调用之前和之后可能需要执行一些操作,所以我不能只执行 return func()
,它同时处理 void
和 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
是一个函数,其中 return 是 void
,foo_return
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>'
据我所知,包装器是正确的,有什么问题吗?我正在使用 is_same
检查函数的 return 类型是否为 void
,如果是,则声明我希望使用 enable_if
的 return 类型。
你有一个语法错误,
-> 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;
}
已经指出了语法错误。不过,我想提一些改进。
因为您正在使用 c++14, you could achieve the same, using a less verbose version of std::enable_if
, by using the helper type std::enable_if_t
其次,std::is_void
is the better(or the suitable) trait from the standard for checking whether a type is void
, which will also save some typing. Using variable templates, (also since c++14), that would be much shorter! (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
}
但是,如果您可以访问 c++17, you could simply write both logic in one function, using if constexpr
. Just for future @todo list. (See live here)
#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
}
}
我正在尝试创建一个转发包装函数,该函数对 c++14 中的函数调用进行计时。我需要处理 2
种类型,
一个是为没有 return 值的函数计时,
其他不returning
我在这里跳过的调用之前和之后可能需要执行一些操作,所以我不能只执行 return func()
,它同时处理 void
和 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
是一个函数,其中 return 是 void
,foo_return
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>'
据我所知,包装器是正确的,有什么问题吗?我正在使用 is_same
检查函数的 return 类型是否为 void
,如果是,则声明我希望使用 enable_if
的 return 类型。
你有一个语法错误,
-> 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;
}
因为您正在使用 c++14, you could achieve the same, using a less verbose version of std::enable_if
, by using the helper type std::enable_if_t
其次,std::is_void
is the better(or the suitable) trait from the standard for checking whether a type is void
, which will also save some typing. Using variable templates, (also since c++14), that would be much shorter! (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
}
但是,如果您可以访问 c++17, you could simply write both logic in one function, using if constexpr
. Just for future @todo list. (See live here)
#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
}
}