I am trying to wrap my head around parameter packs and need a little help.
Looking at the contrived example below, Is there a way to compare Args to T and only allow bar() to compile if they match? For example if I create Task<void(int, char, float)> I want bar(float, char, float) not to compile but bar(int, char, float) to compile just fine. Is this even feasible?
template <typename... Types>
struct foo {};
template<typename T>
struct Task;
template<typename R, typename...Args>
struct Task<R(Args...)>
{
template<typename... T>
std::enable_if<is_same<T, Args>
void bar(T... args)
{
//do something here
}
};
int main()
{
Task<int(int)> task;
int a = 0;
float b = 1.0;
bool c = false;
//compiles
task.bar(a);
//none of these should compile
task.bar(b);
task.bar(c);
task.bar(a, b);
task.bar(a, b, c);
}
First, syntax should be:
template<typename R, typename...Args>
struct Task<R(Args...)>
{
template<typename... T>
std::enable_if<is_same<tuple<T...>, tuple<Args...> >::value > bar(T... args)
{
//do something here
}
};
Which compiles fine, because of SFINAE: while trying to instantiate bar(bool) for example, first instantiation fails with bool type, but an instantiation exists when performing conversion of parameter to int.
To get desired effect, you need the hard type check to happen after instantiating the template:
#include <type_traits>
#include <tuple>
template<typename T>
struct Task;
template<typename R, typename... Args>
struct Task<R(Args...)>
{
template<typename... OtherArgs>
void bar(OtherArgs... otherArgs)
{
static_assert(
std::is_same<std::tuple<Args...>, std::tuple<OtherArgs...> >::value,
"Use same args types !"
);
// Do something
}
};
int main()
{
Task<int(int)> task;
// Compiles fine
task.bar(1);
// Fails to compile
task.bar('u');
task.bar(0ul);
return 0;
}
Related
I have the following code that works in VS2017:
template <typename ... Args>
struct Composite: Args...
{
using Composite<Args...>::foo;
void foo(float exposure)
{
return this->foo(*this, exposure);
}
void internalBar(float e) { std::cout << "it works" << e; }
};
it is used in this way:
struct A
{
template <typename T>
void foo(T& device, float exposure)
{
device.internalBar(exposure);
}
};
struct B
{};
struct C
{};
int main(int argc, char *argv[])
{
auto u = Composite<A, B, C>();
u.foo(5.0f);
return 0;
}
The problem is with the line using Composite<Args...>::foo because is not in the c++ standard. That's why it does not works with gcc: Composite<Args...> is not a base class of Composite.
I had to use this line because Composite hides the foo of A.
How can i pull in the scope of a single packed parameter?
Thanks.
You can solve lots of problems by adding a level of indirection.
template <typename ... Args>
struct CompositeFooWrapper: Args...
{
};
template <typename ... Args>
struct Composite: CompositeFooWrapper<Args...>
{
using CompositeFooWrapper<Args...>::foo;
Demo: https://godbolt.org/z/ddsKc3rvx
I know one could check the existence of a particular method using expression SFINAE in C++11 as follows.
What I can't find though, is an example to do the same, checking method arguments as well. In particular I would like to match a method that takes a const parameter.
#include <iostream>
struct A
{
void method() const
{
return;
}
};
template <typename T, typename = std::string>
struct hasMethod
: std::false_type
{
};
template <typename T>
struct hasMethod<T, decltype(std::declval<T>().method())>
: std::true_type
{ };
int main() {
std::cout << hasMethod<A>::value << std::endl;
}
In reality I would like the hasMethod:: to match
void method(const Type& t) const
{
return;
}
What is the syntax to pass to decltype?
I have tried:
struct hasMethod<T, decltype(std::declval<T>().method(const int&))>
: std::true_type
but it obviously doesn't work.
I'm working on my own Lua engine with C++ 11, I want to write a function wrapper that register C++ function to Lua environment with variadic parameter. That's simple in C++ 0x, but boring cause I need to write similar codes to support function with 0~N parameters.
function push is used to push T to lua stack, where function upvalue_ get C++ function pointer with lua cclosure, and it assume the funtion is has two parameters T1 and T2, T1 is acquired from lua stack with index 1, and T2 is acquired from lua stack with index 2.
template <typename RVal, typename T1, typename T2>
struct functor<RVal,T1,T2>
{
static int invoke(lua_State *L)
{
push(L,upvalue_<RVal(*)(T1,T2)>(L)(read<T1>(L,1),read<T2>(L,2)));
return 1;
}
};
template<typename T>
T upvalue_(lua_State *L)
{
return user2type<T>::invoke(L, lua_upvalueindex(1));
}
and with C++ 11, I wrote such code snippets:
template< typename RVal, typename ... ARGS>
struct functor
{
static int invoke(lua_State* L)
{
typedef RVal (*FUNC_PTR)(ARGS...);
FUNC_PTR f = upvalue_<FUNC_PTR>(L);
push(L, f(read_stack<ARGS>(L)...));
return 1;
}
};
template<typename T>
T read_stack(lua_State* L)
{
T t = read<T>(L, -1);
lua_pop(L, 1);
return t;
}
the code shown above could work, but the parameter order is reversed because read_stack read parameter from the last index -1 always.
my question is how to read parameter from lua stack from 1 to N(N equals to sizeof...(ARGS) if ARGS not empty) with variadic template argument and pass them to real function pointer f to make real call?
Not specific to Lua, here is a general-purpose C++11 solution to reversing the order of given parameters to a function. In the below code, 'apply' is my example target function (here it just outputs a bit of text based on its variadic parameters). The 'main' functions shows how the helper function 'reverse_and_apply' takes a function (or Functor to be precise) and a set of arguments, and applies the given function to the reversed argument list using some template trickery. Note I apologise for the somewhat anal use of perfect forwarding here, which is technically correct but unfortunately obfuscates the code somewhat. Hopefully you get the main message.
#include <iostream>
template <typename ...Args>
void apply(const char* fmtString, const Args&... args)
{
char output[512];
snprintf(output, 512, fmtString, args...);
std::cout << output << std::endl;
}
template <typename F, typename ...Args>
struct ReverseAndApply;
template <typename F>
struct ReverseAndApply<F>
{
template <typename ... AlreadyReversed>
static void doIt(F func, AlreadyReversed&& ... args)
{
func(args...);
}
};
template <typename F, typename FirstArg, typename ...RestArgs>
struct ReverseAndApply<F, FirstArg, RestArgs...>
{
template <typename ... AlreadyReversed>
static void doIt(F func, FirstArg&& arg, RestArgs&& ... restArgs, AlreadyReversed&& ... revArgs)
{
ReverseAndApply<F, RestArgs...>::doIt(func, std::forward<RestArgs>(restArgs)..., std::forward<FirstArg>(arg), std::forward<AlreadyReversed>(revArgs)...);
}
};
template <typename F, typename... Args>
void reverse_and_apply(F func, Args&&... args)
{
ReverseAndApply<F, Args...>::doIt(func, std::forward<Args>(args)...);
}
int main()
{
reverse_and_apply(apply<double, const char*, int>, 1, (const char*)"abc", 2.0, "%f %s %d");
return 0;
}
Your code in C++11 not even work as the evaluation order of arguments is not defined.
It should be easy by using std::integer_sequence in C++14.
Sample code:
template< typename RVal, typename... ARGS>
struct functor
{
template <std::size_t... Is>
static int invoke_impl(lua_State *L, std::index_sequence<Is...>)
{
typedef RVal (*FUNC_PTR)(ARGS...);
FUNC_PTR f = upvalue_<FUNC_PTR>(L);
push(L, f(read<ARGS>(L, Is)...));
return 1;
}
static int invoke(lua_State* L)
{
return invoke_impl(L, std::index_sequence_for<ARGS...>{});
}
};
I have the following code:
#include <iostream>
#include <functional>
class test
{
public:
typedef std::function<bool(int)> Handler;
void handler(Handler h){h(5);}
};
class test2
{
public:
template< typename Ret2, typename Ret, typename Class, typename Param>
inline Ret2 MemFn(Ret (Class::*f)(Param), int arg_num)
{
if (arg_num == 1)
return std::bind(f, this, std::placeholders::_1);
}
bool f(int x){ std::cout << x << std::endl; return true;}
};
int main()
{
test t;
test2 t2;
t.handler(t2.MemFn<test::Handler>(&test2::f, 1));
return 0;
}
It works as expected.
I would like to be able to call this:
t.handler(t2.MemFn<test::Handler>(&test2::f));
instead of
t.handler(t2.MemFn<test::Handler>(&test2::f, 1));
Basically I need MemFn to determine in runtime what Handler expects as the number of arguments.
Is that even possible?
You may create some type_traits to have your info, something like:
template <typename T> struct function_trait;
template <typename Ret, typename ... Args>
struct function_trait<std::function<Ret(Args...)>>
{
static constexpr std::size_t args_count = sizeof...(Args);
};
And so your method may look like:
template<typename Ret2, typename Ret, typename Class, typename Param>
inline Ret2 MemFn(Ret (Class::*f)(Param))
{
if (function_trait<Ret2>::args_count == 1)
return std::bind(f, this, std::placeholders::_1);
throw std::runtime_error("invalid number of arguments");
}
I'm trying to implement a zip function. zip's parameters are each wrapped<Ti>, where Ti varies from parameter to parameter.
zip takes these wrapped<Ti>s and produces a wrapped<tuple<T1&,T2&,...TN&>>, or in other words a wrapped tuple of references to its parameters. The references should preserve const-ness.
Here's my first stab at zip with one parameter, which doesn't work in general:
#include <utility>
#include <tuple>
// implement forward_as_tuple as it is missing on my system
namespace ns
{
template<typename... Types>
std::tuple<Types&&...>
forward_as_tuple(Types&&... t)
{
return std::tuple<Types&&...>(std::forward<Types>(t)...);
}
}
template<typename T>
struct wrapped
{
wrapped(T &&x)
: m_x(std::forward<T>(x))
{}
T m_x;
};
template<typename T>
wrapped<std::tuple<T&&>>
zip(wrapped<T> &&x)
{
auto t = ns::forward_as_tuple(std::forward<T>(x.m_x));
return wrapped<std::tuple<T&&>>(t);
}
int main()
{
wrapped<int> w1(13);
wrapped<int> &ref_w1 = w1;
// OK
zip(ref_w1);
const wrapped<int> &cref_w1 = w1;
// XXX won't compile when passing a const reference
zip(cref_w1);
return 0;
}
Is there a way to implement the general, variadic case with a single version of zip?
Admittedly, I don't have a C++0x compiler that handles variadic templates, so I can't test it. But this might do the trick.
template<typename T>
struct wrapped
{
wrapped(T &&x)
: m_x(std::forward<T>(x))
{}
typedef T type;
T m_x;
};
template<typename... Types>
wrapped<std::tuple<Types&&...>> zip(wrapped<Types>&&... x)
{
return wrapped<std::tuple<Types&&...>>(std::tuple<Types&&...>(std::forward<Types>(x.m_x)...));
}
I'm not entirely sure if it is legal to call zip like this:
zip(wrapped<T1>(value1), wrapped<T2>(value2));
You may have to explicitly qualify the call:
zip<T1, T2>(wrapped<T1>(value1), wrapped<T2>(value2));
Here's the solution I arrived at:
#include <utility>
#include <tuple>
#include <cassert>
template<typename T>
struct wrapped
{
wrapped(T &&x)
: m_x(std::forward<T>(x))
{}
T m_x;
};
template<typename Tuple>
wrapped<Tuple> make_wrapped_tuple(Tuple &&x)
{
return wrapped<Tuple>(std::forward<Tuple>(x));
}
template<typename... WrappedTypes>
decltype(make_wrapped_tuple(std::forward_as_tuple(std::declval<WrappedTypes>().m_x...)))
zip(WrappedTypes&&... x)
{
return make_wrapped_tuple(std::forward_as_tuple(x.m_x...));
}
int main()
{
wrapped<int> w1(1);
wrapped<int> w2(2);
wrapped<int> w3(3);
wrapped<int> w4(4);
auto z1 = zip(w1,w2,w3,w4);
z1.m_x = std::make_tuple(11,22,33,44);
assert(w1.m_x == 11);
assert(w2.m_x == 22);
assert(w3.m_x == 33);
assert(w4.m_x == 44);
const wrapped<int> &cref_w1 = w1;
auto z2 = zip(cref_w1, w2, w3, w4);
// does not compile, as desired
// z2.m_x = std::make_tuple(111,222,333,444);
return 0;
}
Having zip take WrappedTypes... instead of wrapped<T>... isn't as satisfying a solution, but it works.
template<typename T>
struct wrapped
{
wrapped(T &&x)
: m_x(std::forward<T>(x))
{}
typedef T type;
T m_x;
};
template<typename... Types>
wrapped<std::tuple<T&&...>> zip(wrapped<Types>... &&x)
{
return G+