//
// We implement an 'invoke' function for functions of the RPC handler
// signature, i.e. int(R & r, const Args...)
-//
-// One thing we need in order to accomplish this is a way to cause the compiler
-// to specialize 'invoke' with a parameter pack containing a list of indices
-// for the elements of the tuple. This will allow us to call the underlying
-// function with the exploded contents of the tuple. The empty type
-// tuple_indices<size_t...> accomplishes this. It will be passed in to
-// 'invoke' as a parameter which will be ignored, but its type will force the
-// compiler to specialize 'invoke' appropriately.
// This class encapsulates the default response to runtime unmarshalling
// failures. The templated wrappers below may optionally use a different
struct VerifyOnFailure {
static inline int unmarshall_args_failure() {
VERIFY(0);
- return 0;
}
};
// One for function pointers...
template <class F, class R, class RV, class args_type, size_t... Indices>
-typename enable_if<!is_member_function_pointer<F>::value, RV>::type inline
-invoke(RV, F f, void *, R & r, args_type & t, tuple_indices<Indices...>) {
- return f(r, get<Indices>(t)...);
+typename enable_if<!std::is_member_function_pointer<F>::value, RV>::type inline
+invoke(RV, F f, void *, R & r, args_type & t, std::index_sequence<Indices...>) {
+ return f(r, std::get<Indices>(t)...);
}
// And one for pointers to member functions...
template <class F, class C, class RV, class R, class args_type, size_t... Indices>
-typename enable_if<is_member_function_pointer<F>::value, RV>::type inline
-invoke(RV, F f, C *c, R & r, args_type & t, tuple_indices<Indices...>) {
- return (c->*f)(r, get<Indices>(t)...);
+typename enable_if<std::is_member_function_pointer<F>::value, RV>::type inline
+invoke(RV, F f, C *c, R & r, args_type & t, std::index_sequence<Indices...>) {
+ return (c->*f)(r, std::get<Indices>(t)...);
}
// The class marshalled_func_imp uses partial template specialization to
// This type definition represents storage for f's unmarshalled
// arguments. decay is (most notably) stripping off const
// qualifiers.
- using ArgsStorage = tuple<typename decay<Args>::type...>;
+ using ArgsStorage = tuple<typename std::decay<Args>::type...>;
// Allocate a handler (i.e. function) to hold the lambda
// which will unmarshall RPCs and call f.
return new handler([=](unmarshall && u, marshall & m) -> RV {
// Unmarshall each argument with the correct type and store the
// result in a tuple.
- ArgsStorage t{u._grab<typename decay<Args>::type>()...};
+ ArgsStorage t{u._grab<typename std::decay<Args>::type>()...};
// Verify successful unmarshalling of the entire input stream.
if (!u.okdone())
return (RV)ErrorHandler::unmarshall_args_failure();
// Allocate space for the RPC response -- will be passed into the
// function as an lvalue reference.
R r;
- // Perform the invocation. Note that TUPLE_INDICES calls the
- // default constructor of an empty struct with template parameters
- // running from 0 up to (# args) - 1.
- RV b = invoke(RV(), f, c, r, t, TUPLE_INDICES(Args));
+ // Perform the invocation.
+ RV b = invoke(RV(), f, c, r, t, std::index_sequence_for<Args...>{});
// Marshall the response.
m << r;
// Make like a tree.