[英]In C++ 11, how do I specialize a function template that takes a function object based on return type?
我在C ++ 11中有一個包裝函數,設計用於lambdas,如下所示:
template<typename Func>
int WrapExceptions(Func&& f)
{
try
{
return f();
}
catch(std::exception)
{
return -1;
}
}
我可以這樣稱呼它:
int rc = WrapExceptions([&]{
DoSomething();
return 0;
});
assert(rc == 0);
生活還可以。 但是,我想要做的是重載或專門化包裝函數,這樣當內部函數返回void時,外部函數返回默認值0,例如:
int rc = WrapExceptions([&]{
DoSomething();
});
assert(rc == 0);
我可以在C ++ 11中實際執行此操作嗎? 我不能為我的生活思考如何。
您可以使用SFINAE:
使用std::result_of
template<typename Func> typename std::enable_if< std::is_convertible<typename std::result_of<Func()>::type, int>::value, int >::type WrapExceptions(Func&& f) { try { return f(); } catch(std::exception) { return -1; } } template<typename Func> typename std::enable_if< std::is_same<void, typename std::result_of<Func()>::type>::value, int >::type WrapExceptions(Func&& f) { try { f(); return 0; /* default value */ } catch(std::exception) { return -1; } }
與decltype
:
template<typename Func> auto WrapExceptions(Func&& f) -> typename std::enable_if< std::is_convertible<decltype(f()), int>::value, int >::type { try { return f(); } catch(std::exception) { return -1; } } template<typename Func> auto WrapExceptions(Func&& f) -> typename std::enable_if< std::is_same<void, decltype(f())>::value, int >::type { try { f(); return 0; } catch(std::exception) { return -1; } }
也許有點過度設計,但你可以使用標簽調度:
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace detail
{
struct returns_convertible_to_int {};
struct returns_void {};
template<typename Func>
int WrapException_dispatch(Func&& f, returns_convertible_to_int)
{
return f();
}
template<typename Func>
int WrapException_dispatch(Func&& f, returns_void)
{
f();
return 0;
}
template<typename T, typename dummy = void>
struct dispatch
{
static_assert(std::is_same<T, void>::value,
"Incompatible return type");
};
template<typename T>
struct dispatch<T,
typename std::enable_if< std::is_convertible<T, int>{} >::type>
{
using type = returns_convertible_to_int;
};
template<typename T>
struct dispatch<T,
typename std::enable_if< std::is_same<T, void>{} >::type>
// alt: template<> struct dispatch<void,void>
{
using type = returns_void;
};
}
template<typename Func>
int WrapException(Func&& f)
{
try
{
return detail::WrapException_dispatch( std::forward<Func>(f),
typename detail::dispatch<decltype(f())>::type{} );
}
catch(std::exception const&) { return -1; }
}
用法示例:
int foo() { return 42; }
void bar() {}
int main()
{
WrapException(foo);
WrapException(bar);
}
當然,您可以實施更短的調度:
namespace detail
{
template<typename Func>
auto WrapException_dispatch(Func&& f, int)
-> typename std::enable_if<
std::is_convertible<decltype(f()), int>::value, int
>::type
{
return f();
}
template<typename Func>
int WrapException_dispatch(Func&& f, ...)
{
f();
return 0;
}
}
template<typename Func>
int WrapException(Func&& f)
{
try
{
return detail::WrapException_dispatch( std::forward<Func>(f), 0 );
}
catch(std::exception const&) { return -1; }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.