I'm really happy with the perfect forwarding in C++11 and want to do something more complicated. It's somewhat a classic case. I have a template axis-aligned box class. The template argument is a vector class. So I have a classic constructor, that takes 2 vectors:
template <class T> struct base_vec2 {
typedef T scalar_type;
base_vec2 (T a, T b); // counsruct for two scalar calues
};
template <class T> struct base_vec3 {
typedef T scalar_type;
base_vec2 (T a, T b, T c); // counsruct for three scalar calues
};
template <class T> struct base_box {
typedef typename T::scalar_type scalar_type;
T lower, upper; //<! upper and lower point
base_box<T> (const T& min, const T& max);
};
base_box<base_vec3<float>> box;
Naturally, one may want to implement a constructor which takes n scalar values and pass them to the lower and upper constructors. This is what I came up with:
template <class T> struct base_box {
.....
template <typename... Ts> base_box<T> (scalar_type s1, scalar_type s2, scalar_type s3, scalar_type s4, Ts&&... ts) {
base_box_construct<T, scalar_type, (4 + sizeof...(ts))/2> _(lower, upper, s1, s2, s3, s4, std::forward<Ts>(ts)...);
}
};
base_box<base_vec2<float>> box(1, 2, 3, 4);
base_box<base_vec3<float>> box(1, 2, 3, 4, 5, 6);
base_box_construct do the actual magic:
template <class T, class A>
struct base_box_construct<T, A, 2> {
template <typename... Ts>
base_box_construct(T& lower, T& upper, A s1, A s2, A s3, A s4, Ts&&... ts)
{
lower = T(a1, a2);
upper = T(a3, a4);
}
};
template <class T, class A>
struct base_box_construct<T, A, 3> {
template <typename... Ts>
base_box_construct(T& lower, T& upper, A s1, A s2, A s3, A s4, Ts&&... ts)
{
lower = T(s1, s2, s3);
upper = T(s4, std::forward<Ts>(ts)...);
}
};
template <class T, class A>
struct base_box_construct<T, A, 4> {
template <typename... Ts>
base_box_construct(T& lower, T& upper, A s1, A s2, A s3, A s4, Ts&&... ts)
{
lower = T(s1, s2, s3, s4);
upper = T(std::forward<Ts>(ts)...);
}
};
It's a bit tricky, since it works only with 2, 3 and 4 arguments per vector which is just what I need. But I was wondering if there is better way to implement it.
You can just use uniform initialization, no further changes required:
base_box<base_vec3<float>> box { { 1,2,3 }, { 4,5,6 } };
The standard does this in similar ways using std::piece_wise_construct_t
Live On Coliru
template <class T> struct base_vec2 {
typedef T scalar_type;
T a, b;
base_vec2 (T a, T b) : a(a), b(b) {} // construct for two scalar calues
};
template <class T> struct base_vec3 {
typedef T scalar_type;
T a, b, c;
base_vec3 (T a, T b, T c) : a(a), b(b), c(c) {} // construct for three scalar calues
};
template <class T> struct base_box {
typedef typename T::scalar_type scalar_type;
T lower, upper; //<! upper and lower point
base_box<T> (const T& min, const T& max)
: lower(min), upper(max)
{ }
};
int main() {
base_box<base_vec3<float>> box { { 1,2,3 }, { 4,5,6 } };
}
Related
I need to define a function with template parameter pack with C++14.
The caller of the function makes sure that the size of Args... must be even, such as 2, 4, 6... And my function will pass them two by two to two functions.
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... params) {
using params_t = std::tuple<Args...>;
auto tp = std::make_tuple(params...);
for (std::size_t i = 0; i < sizeof...(Args); ++i) {
f(std::get<i>(tp));
f2(std::get<++i>(tp));
}
}
// caller
func(f1, f2, "abc", 3, "def", "ppp");
This won't work because i is not a constant expression.
What could I do? Is it the right and the only way to iterate over a parameter pack with std::tuple?
To use a std::tuple to iterate over a parameter pack, you would usually use a std::index_sequence to introduce a new pack of indices, and use a fold expression to do the actual iteration. Something like this:
template<typename F, typename F2, typename... Args, std::size_t... I>
void func_impl(F& f, F2& f2, std::tuple<Args...> params, std::index_sequence<I...>) {
// This would be a fold expression over a comma in C++17:
/*
(([&]{}(
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
)), ...);
*/
// C++14 version
using consume = int[];
(void) consume{ 0, [&]{
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
return 0;
}()... };
}
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... args) {
static_assert(sizeof...(args) % 2 == 0, "Must pass a multiple of 2 args to func");
func_impl(
f, f2,
std::forward_as_tuple(std::forward<Args>(args)...),
std::make_index_sequence<sizeof...(args) / 2>{}
);
}
But you can also iterate with recursion, which might be easier in your case:
template<typename F, typename F2>
void func(F&& f, F2&& f2) {
// base case: do nothing
}
template<typename F, typename F2, typename Arg1, typename Arg2, typename... Args>
void func(F&& f, F2&& f2, Arg1&& arg1, Arg2&& arg2, Args&&... args) {
// recursive case
f(arg1);
f2(arg2);
func(std::forward<F>(f), std::forward<F2>(f2), std::forward<Args>(args)...);
}
Consider I have the following:
void bar(int a, int b)
{
}
template<typename F, typename... Args>
void foo(F function, Args... args>
{
function(args...);
}
I would like to have some kind of way to only pass the necessary amount of arguments to the function, so that I would be able to do the following, which should result in a call to bar with 1, 2 as arguments discarding the 3. Without knowing how many arguments the passed in function type F needs.
foo(bar, 1, 2, 3);
foo([](int a, int b){}, 1, 2, 3);
When I try to use the below function traits:
namespace detail
{
template<typename F, std::size_t... Is, class Tup>
void call_discard_impl(F&& func, std::index_sequence<Is...>, Tup&& tup)
{
std::forward<F>(func)(std::get<Is>(tup)...);
}
}
template<typename F, typename... Args>
void call_discard(F&& func, Args&&... args)
{
detail::call_discard_impl(std::forward<F>(func),
std::make_index_sequence<function_traits<F>::num_args>{},
std::forward_as_tuple(args...));
}
I get:
error C2510: 'F': left of '::' must be a class/struct/union
error C2065: '()': undeclared identifier
error C2955: 'function_traits': use of class template requires template argument list
On:
template <typename F>
struct function_traits : public function_traits<decltype(&F::operator())>
{}
I did get the member function version working which did not require the function traits:
namespace detail
{
template<typename O, typename R, typename... FunArgs, std::size_t... Is, class Tup>
void call_discard_impl(O* obj, R(O::*mem_func)(FunArgs...), std::index_sequence<Is...>, Tup&& tup)
{
((*obj).*mem_func)(std::get<Is>(tup)...);
}
}
template<typename O, typename R, typename... FunArgs, typename... Args>
void call_discard(O* obj, R(O::*mem_func)(FunArgs...), Args&&... args)
{
detail::call_discard_impl(obj, mem_func,
std::make_index_sequence<sizeof...(FunArgs)>{},
std::forward_as_tuple(args...));
}
First, use the following code that lets you find the arity of a lambda or function reference:
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
using result_type = ReturnType;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
template <typename R, typename ... Args>
struct function_traits<R(&)(Args...)>
{
using result_type = R;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
Next, you forward the variadic arguments along using a tuple pack, and you only expand out to the arity of the function:
template<typename F, std::size_t... Is, class T>
void foo_impl(F && f, std::index_sequence<Is...>, T && tuple) {
std::forward<F>(f)(std::get<Is>(tuple)...);
}
template<typename F, typename... Args>
void foo(F && f, Args&&... args) {
foo_impl(std::forward<F>(f),
std::make_index_sequence<function_traits<F>::arity>{},
std::forward_as_tuple(args...) );
}
Live example: http://coliru.stacked-crooked.com/a/3ca5df7b55c427b8.
First, we need a function to retrieve the number or arguments the function requires. This is done using function_traits:
template <class F>
constexpr std::size_t nb_args() {
return utils::function_traits<F>::arity;
}
And with the help of std::index_sequence, we only dispatch the nb_args<F>() first arguments:
template<typename F, std::size_t... Is, class Tup>
void foo_impl(F && f, std::index_sequence<Is...>, Tup && tup) {
std::forward<F>(f)( std::get<Is>(tup)... );
}
template<typename F, typename... Args>
void foo(F && f, Args&&... args) {
foo_impl(std::forward<F>(f),
std::make_index_sequence<nb_args<F>()>{},
std::forward_as_tuple(args...) );
}
Demo
Trivial and hardly extensible solution would be to create a wrapper, that will be called with all arguments, but will use only first few of them.
template<typename F, typename... Args>
void foo(F function, Args... args)
{
// with proper forwarding if needed
auto lambda = [](auto fnc, auto first, auto second, auto...)
{
fnc(first, second);
};
lambda(function, args...);
}
Here is a solution that will work with anything std::invoke accepts, that invokes the overload with the fewest possible arguments.
template <typename F, typename Args, std::size_t... In>
decltype(auto) invoke_front_impl(F&& f, Args&& args, std::index_sequence<In...>)
{
if constexpr (std::is_invocable_v<F&&, std::tuple_element_t<In, Args>...>) {
return std::invoke(std::forward<F>(f), std::get<In>(std::move(args))...);
} else {
return invoke_front_impl(
std::forward<F>(f),
std::move(args),
std::make_index_sequence<sizeof...(In) + 1>());
}
}
template <typename F, typename... Args>
decltype(auto) invoke_front(F&& f, Args&&... args)
{
return invoke_front_impl(
std::forward<F>(f),
std::forward_as_tuple(std::forward<Args>(args)...),
std::make_index_sequence<0>());
}
Demo on Wandbox
I would like to use boost::range::combine as a cartesian power instead as just a product.
So instead of such expression boost::range::combine(myRange, myRange, myRange); write something like myCombine(myRange, 3);.
How it can be implemented?
Implementing this in C++17 or C++14 would be a lot easier and cleaner, but since you tagged this with c++11 here's a compliant implementation. Here's a generic way of calling a function object f with the same argument repeated N times.
First, we need a way of binding the first argument of a generic function object f and then accepting any number of arguments:
template <typename TF, typename T>
struct bound
{
TF _f;
T _x;
template <typename TFFwd, typename TFwd>
bound(TFFwd&& f, TFwd&& x)
: _f{std::forward<TFFwd>(f)}, _x{std::forward<TFwd>(x)}
{
}
template <typename... Ts>
auto operator()(Ts&&... xs)
-> decltype(_f(_x, std::forward<Ts>(xs)...))
{
return _f(_x, std::forward<Ts>(xs)...);
}
};
template <typename TF, typename T>
auto bind_first(TF&& f, T&& x)
-> decltype(bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x)))
{
return bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x));
}
Then, we need a recursive helper that will bind an argument x multiple TN times:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x))
{
return helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(f(x))
{
return f(x);
}
};
Finally, we can provide a nice interface:
template <std::size_t TN, typename TF, typename T>
auto call_with_same_arg(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x)))
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
Usage:
int add(int a, int b, int c)
{
return a + b + c;
}
int main()
{
assert(call_with_same_arg<3>(add, 5) == 15);
}
live wandbox example
Here's a complete C++17 implementation of the same thing:
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
if constexpr(TN == 1)
{
return f(x);
}
else
{
return call_with_same_arg<TN - 1>(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
}
live wandbox example
For completeness, C++14 implementation:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return helper<TN - 1>{}(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return f(x);
}
};
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
live wandbox example
I have a class with a variadic template member function (foo) like below. The idea is to skip all doubles in the parameter and allocate an object with user provided arguments.
template <class T>
class Var {
public:
template <typename U, typename ...Args>
int foo(int index, Args... args)
{
T* p = new U(args...);
// save in an array at index 'index'
}
template <typename U, typename ...Args>
int foo (double index, Args... args)
{
// do something with index and skip it
return foo<U>(args...);
}
};
class A {
public:
A (int i, const char *p)
{
}
};
int main ()
{
Var<A> var;
var.foo<A>(1.0, 2, 3, "Okay");
}
Now this works, there are 2 problem.
Enforce how many doubles to skip.Eg: skip 2 doubles and then the next argument should be an int. If it is not then throw error.
While at it, use 'int' in place of 'double'. So we will skip 2 ints. The next index will be a 'index' to an array.
Basically I want to pass the no. of ints to skip as class template parameter.
template <class T, int SKIP>
class Var {
And use SKIP to determine how many ints to skip.
Is it possible to do something like that?
For your SKIP goal, you could do something like this:
template <typename U, typename ...Args>
int foo(Args ...args) {
return foo_helper<U, 0>(std::forward(args));
}
template <typename U, int I, typename ...Args>
int foo_helper(int index, Args ...args) {
return foo_helper<U, I+1>(std::forward(args));
}
template <typename U, typename ...Args>
int foo_helper<U, SKIP, Args...>(int index, Args ...args) {
blah = new U(std::forward(args));
return foobar;
}
Basically, have methods that count up to the target and strip off arguments until it's reached. Make a specialization for the target value.
Also, not that you'll probably want to forward the arguments to preserve references, etc.
I believe C++14 might make some of this easier, but I'm not familiar enough with newer template metaprogramming techniques to address that.
So this is what I conjured up taking hint from Novelocrat. Just pasting it hear for the records.
template <class T, int SKIP>
class FooHelper {
public:
template <typename U, typename ...Args>
static int foo_helper(int index, Args... args)
{
FooHelper<T, SKIP-1>::foo_helper<U>(args...);
return 0;
}
};
template <class T>
class FooHelper<T, 0> {
public:
template <typename U, typename ...Args>
static int foo_helper (Args... args)
{
auto p = new U(args...);
return 0;
}
};
template <class T, int SKIP>
class Var {
public:
template <typename U, typename ...Args>
int foo(Args ...args)
{
FooHelper<T, SKIP>::foo_helper<U>(args...);
return 0;
}
};
I have the following scenario:
struct AP;
struct B
{
B() : m(2) {}
int m;
};
struct A : private B
{
A() : B(), n(1) {}
private:
int n;
friend AP;
};
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
struct A_B {
using type = typename std::enable_if< std::is_base_of< typename std::remove_reference<T>::type,
A >::value,
T >::type;
};
template<typename T>
operator typename A_B<T>::type()
{
return static_cast<T>(a_);
}
template<typename T>
typename A_B<T>::type get()
{
return static_cast<T>(a_);
}
int& n() { return a_.n; }
private:
A& a_;
};
int main()
{
A a;
AP ap(a);
ap.n() = 7;
const B& b = ap.get<const B&>();
//const B& b = ap; candidate template ignored: couldn't infer template argument 'T'
//auto b = static_cast<const B&>(ap); candidate template ignored: couldn't infer template argument 'T'
std::cout<<b.m;
}
The commented lines wouldn't compile. Clang++ notes that "candidate template ignored: couldn't infer template argument 'T'"
Why am I not able to get a reference to A's base with the cast operator?
I think the code would look much nicer that way.
The answer that you posted works, but is overkill unless you really want a static_assert message.
Classic templating works just fine in this instance because A is already convertible to B:
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
operator T()
{
return a_;
}
template<typename T>
T get()
{
return a_;
}
int& n() { return a_.n; }
private:
A& a_;
};
Demo
I found the answer here: http://www.mersenneforum.org/showthread.php?t=18076
This is the key: "when you want the compiler to deduce argument types, those types must not be dependent types"
With this it compiles:
template<typename T>
operator T()
{
static_assert(std::is_base_of< typename std::remove_reference<T>::type,A >::value,
"You may cast AP only to A's base classes.");
return static_cast<T>(a_);
}