I'm writing a simple "wrapper library" around another library and I'm having issues with std::function not being able to deduce template arguments for variadic template functions. To make things more concrete:
main
in the code below for examples.Here's the complete example (that doesn't compile):
#include <type_traits>
#include <variant>
#include <vector>
/*** Library code starts here ***/
// Library handler function definition to be registered. This cannot be changed.
// For simplicity I made the function arguments (int, int) to denote that this
// handler function does take some arguments passed later by the library.
// In reality these are simple, non-templated structs.
using LibraryHandler = std::function<void(int, int)>;
std::vector<LibraryHandler> g_libraryHandlers;
void RegisterLibraryHandler(LibraryHandler handler)
{
// Library code registering passed handler. This cannot be changed.
g_libraryHandlers.push_back(handler);
}
/*** End of library code ***/
/*** My "wrapper library" starts here ***/
// ReturnType is the type returned by the functions written by "wrapper library users".
// Types... is the list of all possible types held by 'ReturnType' that a given function is allowed to return.
template<typename T, typename... Types>
static inline constexpr bool isConstructible = (std::is_constructible_v<T, Types> || ...);
template<typename T, typename... Types>
static inline constexpr bool isAssignable = (std::is_assignable_v<T&, Types> || ...);
template<typename... Types>
class ReturnType
{
public:
template<typename T, std::enable_if_t<
isConstructible<T, Types...> &&
isAssignable<T, Types...>,
int> = 0>
static ReturnType Build(const T& data)
{
return ReturnType(data);
}
private:
template<typename T>
ReturnType(const T& data) : m_data(data) { }
std::variant<Types...> m_data;
};
template<typename T>
class ParamType
{
public:
ParamType() { }
const T& GetData() const { return m_data; }
private:
T m_data;
};
/*** This is where my problem is - how to write these functions to allow for
different logic (based on passed function signature) inside nested lambda? ***/
// Version registering functions taking no arguments
template<typename... Types>
void RegisterFunction(std::function<ReturnType<Types...>()> func)
{
auto wrapperLambda = [func](int a, int b) { // Construct lambda to conform with library interface ('LibraryHandler')
// Logic specific for 'func' with signature: ReturnType<Types...>() - step before call
func();
// Logic specific for 'func' with signature: ReturnType<Types...>() - step after call
};
RegisterLibraryHandler(wrapperLambda); // Register lambda inside library
}
// Version registering functions taking arguments through 'ParamType'
template<typename... Types, typename TParam>
void RegisterFunction(std::function<ReturnType<Types...>(const ParamType<TParam>)> func)
{
auto wrapperLambda = [func](int a, int b) { // Construct lambda to conform with library interface ('LibraryHandler')
// Logic specific for 'func' with signature: ReturnType<Types...>(const ParamType<TParam>) - step before call
func();
// Logic specific for 'func' with signature: ReturnType<Types...>(const ParamType<TParam>) - step after call
};
RegisterLibraryHandler(wrapperLambda); // Register lambda inside library
}
// Version registering functions taking library arguments directly
template<typename... Types, typename TParam>
void RegisterFunction(std::function<ReturnType<Types...>(int, int)> func)
{
auto wrapperLambda = [func](int a, int b) { // Construct lambda to conform with library interface ('LibraryHandler')
// Logic specific for 'func' with signature: ReturnType<Types...>(int, int) - step before call
func(a, b);
// Logic specific for 'func' with signature: ReturnType<Types...>(int, int) - step after call
};
RegisterLibraryHandler(wrapperLambda); // Register lambda inside library
}
/*** End of my "wrapper library" ***/
/*** This is how I'd like the "users of the wrapper library" to write the code ***/
struct SomeReturnData { char a; char b; };
struct OtherReturnData { char c; char d; };
struct SomeParameterType { int p; };
// Example 1 - function only ever returning a single type, taking no arguments
ReturnType<SomeReturnData> UserFunctionNoArgs()
{
SomeReturnData data{ 'x', 'y' };
return ReturnType<SomeReturnData>::Build(data);
}
// Example 2 - function taking parameter 'SomeParameterType' and returning 'SomeReturnData' or 'OtherReturnData'
// based on contents of passed argument.
ReturnType<SomeReturnData, OtherReturnData> UserFunctionArgs(const ParamType<SomeParameterType> param)
{
if (param.GetData().p == 1000)
return ReturnType<SomeReturnData, OtherReturnData>::Build(SomeReturnData());
return ReturnType<SomeReturnData, OtherReturnData>::Build(OtherReturnData());
}
// Example 3 - function requesting library arguments to be passed directly
ReturnType<SomeReturnData, OtherReturnData> UserHandlingLibraryDirectly(int libraryArg1, int libraryArg2)
{
if (libraryArg1 == libraryArg2)
return ReturnType<SomeReturnData, OtherReturnData>::Build(SomeReturnData());
return ReturnType<SomeReturnData, OtherReturnData>::Build(OtherReturnData());
}
int main()
{
// User registers written functions in the "wrapper library".
// This includes any 'regluar functions'...
RegisterFunction(UserFunctionNoArgs);
RegisterFunction(UserFunctionArgs);
RegisterFunction(UserHandlingLibraryDirectly);
// ... or lambdas with captures (all possible parameter combinations from examples above apply).
int someInt = 123;
auto userLambda = [someInt]() -> ReturnType<SomeReturnData, OtherReturnData> {
if(someInt < 100)
return ReturnType<SomeReturnData, OtherReturnData>::Build(SomeReturnData());
return ReturnType<SomeReturnData, OtherReturnData>::Build(OtherReturnData());
};
return 0;
}
My issue is with the RegisterFunction
above - I'd basically want to write it the way it is above, which is obviously not possible (the compiler complains about not being able to deduce template parameters). My goal is to not change / cut down on possibilities / make any more complicated anything that's inside main
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.