My function calls a Python function with a set of given input arguments (variadic) and returns a tuple containing the function's output (variadic because output varies on the function called).
I'm compiling on a Windows 10 machine via MinGW-w64 compiler's port of g++ using C++11. I've declared this templated variadic function (and call it) as follows:
// Declaration (in PyInterface.h)
template <typename... Inputs, typename... Outputs>
const std::tuple<Outputs...>& callFunction(const std::string &modulePath, const std::string &funcName, Inputs&&... args) {
// Calls a Python function & packs output variables into a std::tuple...
}
// Sample call (in main.cpp)
const std::tuple<std::string, std::string> output = pi.callFunction(myModulePath, myFuncName, inputArg1, inputArg2, inputArg3);
However, this error is thrown (shortened with ...
for readability):
conversion from 'const std::tuple<>' to non-scalar type 'const std::tuple<std::__cxx11::basic_string<...>, std::__cxx11::basic_string<...> >' requested
As far as I'm aware using two variadic templates is legal. Additionally, it seems to me that the return type is explicitly set by the variable (const std::tuple<std::string, std::string> output
) I am attempting to assign the result of the function to, so the compiler should know what the desired return
type is.
Originally, I thought that the error simply indicated that I wasn't using the variadic templates appropriately. I tried using nested template parameters (illustrated here) to specify the return type (i.e., const T<Outputs...>& callFunction
). However, this only succeeded in producing an error message indicating that template deduction of T
had failed.
This error indicates that my intuition is wrong and that, in my original function, the compiler isn't deducing the desired return type from output
's type.
Why is my intuition wrong? How do I correctly use a variadic template to specify this function's return type?
If you want to deduce the return type based on the type of an object being returned that is in the scope of the function, if you are on C++14 then you can just use auto
as the return type. It works like a charm
template <typename... Inputs>
const auto& callFunction(
const std::string &modulePath,
const std::string &funcName,
Inputs&&... args) {
return object;
}
As always beware that you are returning a const reference from this function.
If you are using C++11 then you can use trailing return types, for example
template <typename T>
auto identity_return(T& obj) -> decltype(obj) {
return obj;
}
where decltype(obj)
is the type of the thing you want to return. Again beware in this case it is again a reference.
In general though try and return values from a function, returning references can lead to dangling references if you are not sure what you are returning will outlive the return.
Another solution is to just specify the Outputs...
type list manually and let the compiler deduce the types Inputs...
template <typename... Outputs, typename... Inputs>
const std::tuple<Outputs...>& callFunction(
const std::string &modulePath,
const std::string &funcName,
Inputs&&... args) { ... }
auto tup = callFunction<std::string, std::string>(modulePath, funcName, args);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With