I have checked out the related posts to this error and wasn't able to use those solutions to solve my problem. So i have this code that attempts to dynamically create a tuple by converting stringified values to their corresponding types in the array for that I have a generic function that aims to produce that value and add it to the tuple but it seems to be throwing an error whenever I try to generically set its return type.
This the generic function that converts the stringified argument into its actual type (its just a minimal exmaple btw not the whole function i have written in my codebase).
#include <string>
#include <iostream>
#include <tuple>
#include <vector>
#include <type_traits>
template <typename T>
T convertArg(string type, string arg)
{
if (type == "Integer") {
int temp = stoi(arg);
return temp;
} else if (type == "Boolean") {
return arg == "true" ? true : false;
} else {
return arg;
}
};
I have a runtime loop that creates the tuple by using the function above.
namespace detail
{
template <int... Is>
struct seq
{
};
template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...>
{
};
template <int... Is>
struct gen_seq<0, Is...> : seq<Is...>
{
};
template <typename... Ts, int... Is>
tuple<Ts...> for_each(tuple<Ts...> &t, std::vector<string> types, std::vector<string> args, seq<Is...>)
{
// this line throws the error where i try set the return type of the function on the basis of the element at that index in the tuple.
return make_tuple(convertArg<tuple_element<Is, decltype(t)>::type>(types.at(Is), args.at(Is))...);
}
}
template <typename... Ts>
tuple<Ts...> for_each_in_tuple(std::tuple<Ts...> &t, std::vector<string> types, std::vector<string> args)
{
return detail::for_each(t, types, args, detail::gen_seq<sizeof...(Ts)>());
}
int main()
{
std::vector<std::string> types = {"String", "Integer"};
std::vector<std::string> args = {"rehan", "12"};
std::tuple<std::string, int> t;
t = for_each_in_tuple(t, types, args);
cout << "Tuple values" << endl;
cout << get<0>(t) << endl;
cout << get<1>(t) << endl;
}
The complete error as well:
main.cpp:41:38: error: implicit instantiation of undefined template 'std::tuple_element<0, std::tuple<std::string, int> &>'
return make_tuple(convertArg<tuple_element<Is, decltype(t)>::type>(types.at(Is), args.at(Is))...);
I've already looked at the other solution and it didnt work for me and thats why i have asked this question to get a solution related to my particular scenario and btw im on c++ 14
Instead of decltype(t)
it should be std::remove_reference_t<decltype(t)>
but that just leads to the next problem, your convertArg
function will not work. All branches must be valid and if T
is std::string
returning int
isn't valid for example.
I suggest that you drop the vector
with types and just use the information in the tuple
:
template <class T> // primary, just let the string through
T convertArg(const std::string& arg) {
return arg;
}
template <> // specialization for int
int convertArg<int>(const std::string& arg) {
return stoi(arg);
}
template <> // specialization for bool
bool convertArg<bool>(const std::string& arg) {
return arg == "true";
}
namespace detail {
template <typename... Ts, std::size_t... Is>
std::tuple<Ts...> for_each(std::tuple<Ts...>& t,
const std::vector<std::string>& args,
std::index_sequence<Is...>) {
return make_tuple(
convertArg<
std::tuple_element_t<Is, std::remove_reference_t<decltype(t)>>>(
args.at(Is))...);
}
} // namespace detail
template <typename... Ts>
std::tuple<Ts...> for_each_in_tuple(std::tuple<Ts...>& t,
const std::vector<std::string>& args) {
return detail::for_each(t, args, std::index_sequence_for<Ts...>());
}
std::remove_reference_t<decltype(t)>
could also be replaced with std::tuple<Ts...>
.