I have a simple wrapper template that allows free functions (e.g. open()
close()
etc) to passed as template parameters. The code is as follows:
template <auto fn, typename ReturnType=void>
struct func_wrapper {
template<typename... Args>
constexpr ReturnType operator()(Args&&... args) const {
if constexpr( std::is_same<ReturnType, void>::value) {
fn(std::forward<Args>(args)...);
} else {
return fn(std::forward<Args>(args)...);
}
}
};
This is used as follows:
void CloseFunc2(int a);
into OpenFunc2(const std::string&, int flags);
using FileWrapper2 = DevFileWrapper<func_wrapper<OpenFunc2, int>,
func_wrapper<CloseFunc2>>;
The code is working fine but I would like to remove the requirement to manually specify ReturnType
when creating a func_wrapper
.
I tried using std::result_of
but that failed because fn
is a non type template parameter, e.g.:
template<typename... Args>
constexpr auto operator()(Args&&... args) const
-> std::invoke_result<fn(std::forward<Args>(args)...)>::type {
if constexpr( std::is_same<ReturnType, void>::value) {
fn(std::forward<Args>(args)...);
} else {
return fn(std::forward<Args>(args)...);
}
}
the error is:
template-parameter-callable.cpp:48:71: error: template argument for
template type parameter must be a type
constexpr auto operator()(Args&&... args) const ->
std::invoke_result<fn(std::forward<Args>(args)...)>::type {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/
usr/include/c /v1/type_traits:4009:17:
note: template parameter is declared here
template <class _Fn, class... _Args>
^
1 error generated.
How can I deduce the return type of calling fn
at compile time?
CodePudding user response:
template <auto fn>
struct func_wrapper {
template<typename... Args>
constexpr decltype(auto) operator()(Args&&... args) const {
return fn(std::forward<Args>(args)...);
}
};
have you tried this?
I think that works in c 17. Definitely in c 20.
The return type of a callable cannot be determined unless you also know the arguments you are calling it with.
I can extract the return type, but I don't think you need it.
template <auto fn>
struct func_wrapper {
template<typename... Args>
constexpr decltype(auto) operator()(Args&&... args) const {
using ReturnType = std::invoke_result_t<
decltype(fn),
Args&&...
>;
return fn(std::forward<Args>(args)...);
}
};
but as you can see we don't need it.
return f(x)
when f
returns void
is (now) legal.