Here is my simple code and it did work (I passed single integer to argument
):
#include <iostream>
#include <tuple>
#include <string>
#include "boost/variant.hpp"
using TObjList = std::vector<boost::variant<std::string, int>>;
template<typename> struct FTrait;
template<typename R, typename... A> struct FTrait<R(A...)> {
using RetType = R;
using ArgsTuple = std::tuple<A...>;
static constexpr std::size_t arity = sizeof...(A);
template<size_t N> struct argument {
static_assert( N < arity , "error: invalid argument index");
typedef typename std::tuple_element_t<N, std::tuple<A...>> type;
};
};
void Show(const std::string& s, int a) {
std::cout << s << "\n" << a << "\n";
}
int main() {
TObjList list;
list.emplace_back("hello");
list.emplace_back(567);
Show(boost::get<FTrait<decltype(Show)>::argument<0>::type>(list[0]),
boost::get<FTrait<decltype(Show)>::argument<1>::type>(list[1]));
}
But the following code did not work (Maybe I passed a sequence to argument
):
#include <iostream>
#include <tuple>
#include <string>
#include "boost/variant.hpp"
using TObjList = std::vector<boost::variant<std::string, int>>;
template<typename> struct FTrait;
template<typename R, typename... A> struct FTrait<R(A...)> {
using RetType = R;
using ArgsTuple = std::tuple<A...>;
static constexpr std::size_t arity = sizeof...(A);
template<size_t N> struct argument {
static_assert( N < arity , "error: invalid argument index");
typedef typename std::tuple_element_t<N, std::tuple<A...>> type;
};
};
// here is new code
template<typename T> struct ConvertOne {
T operator () (const TObjList& List, size_t Index) {
if ( Index < List.size() ) {
return boost::get<T>(List[Index]);
}
}
};
template<typename F, size_t... Index>
void MyCall(const F& Func, const TObjList& List, const std::index_sequence<Index...>&) {
// This code not work:
Func(ConvertOne<typename FTrait<F>::argument<Index>::type>{}(List, Index)...);
// These code would work:
// using ArgsTuple = typename FTrait<F>::ArgsTuple;
// Func(ConvertOne<std::decay_t<typename std::tuple_element_t<Index, ArgsTuple>>>{}(List, Index)...);
}
// new code done
void Show(const std::string& s, int a) {
std::cout << s << "\n" << a << "\n";
}
int main() {
TObjList list;
list.emplace_back("hello");
list.emplace_back(567);
// new invoke
MyCall(Show, list, std::make_index_sequence<FTrait<decltype(Show)>::arity>{});
}
This code would raise a compile error:
ftrait.cpp: In function ‘void MyCall(const F&, const TObjList&, std::index_sequence<Index ...>&)’:
ftrait.cpp:34:62: error: template argument 1 is invalid
Func(ConvertOne<typename FTrait<F>::argument<Index>::type>{}(List, Index)...);
I hope to use std::index_sequence
and function_traits
to make the program automatically identify the type and number of parameters of a function, like std::tuple_element<Index, ArgsTuple>::type
. boost::function_traits
cannot satisfy me, so I try to implement by myself. What should I do? Thanks :)
CodePudding user response:
In your case, typename FTrait<F>::argument<0>::type
is const std::string&
.
std::get<const std::string&>(list[0])
won't compile- you need
std::get<std::string>(list[0])
.
It might be solved with std::decay
:
template<typename F, size_t... Index>
void MyCall(const F& Func, const TObjList& List, const std::index_sequence<Index...>&)
{
Func(ConvertOne<
typename std::decay<
typename FTrait<F>::template argument<Index>::type
>::type
>{}(List, Index)...);
}