C++, pass two parameter packs to constructor - c++

I have the following problem. I have a class (mixin), that has two template bases.
template <typename T>
class Id
{
using result = T;
};
template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>,
typename Id<Args1>::result... args1,
typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)..., std::forward<Args2>(args2)...)
{}
public:
template <typename... Args, typename =
std::enable_if_t<!contains<dummy, Args...>::result>>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy(), typename Printer1::ArgsCtor(),
typename Printer2::ArgsCtor(), std::forward<Args>(args)...)
{
}
};
All names of classes are fictitious. So, imagine its first base accepts int as constructor argument and second base accepts double. What I want to do is to be able to call constructor of SeveralPrinters like SeveralPrinters(1, 2.). The problem here, is that Args1 and Args2 are deduced not from helper structure, but from args, passed after helper structure. As you can see, I tried to wrap template arguments into Id structure, and that didn't help. I know, it is called smth like Non-deduced contexts, but I couldn't manage to make it work. Can anyone help with it (if it possible), and maybe explain a little bit more on this topic (why it doesn't work now).
Example of base classes:
class BasicPrinter1
{
public:
BasicPrinter1(int)
{}
void f()
{
}
using ArgsCtor = helper<int>;
};
class BasicPrinter2
{
public:
BasicPrinter2(int*)
{}
void g()
{
}
using ArgsCtor = helper<int*>;
};

It doesn't work mainly because the alias result in Id is private (default accessibility for classes), and so not accessible from the private constructor of SeveralPrinters, leading to a substitution failure (typename Id<Args1>::result) with no other viable candidate constructor to call. There were also a couple of typos in your code.
template <typename T>
struct Id
{
using result = T;
};
template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <typename... Args1, typename... Args2>
SeveralPrinters(dummy, helper<Args1...>, helper<Args2...>
, typename Id<Args1>::result... args1
, typename Id<Args2>::result... args2)
: Printer1(std::forward<Args1>(args1)...)
, Printer2(std::forward<Args2>(args2)...)
{}
public:
template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(dummy{}
, typename Printer1::ArgsCtor{}
, typename Printer2::ArgsCtor{}
, std::forward<Args>(args)...)
{}
};
DEMO
In order to perfectly-forward the arguments to base classes, you should instead declare the number of parameters (ArgsCount) and use the below implementation:
template <typename Printer1, typename Printer2>
class SeveralPrinters : public Printer1, public Printer2
{
template <std::size_t... Is
, std::size_t... Js
, typename... Args>
SeveralPrinters(std::index_sequence<Is...>
, std::index_sequence<Js...>
, std::tuple<Args...>&& t)
: Printer1(std::get<Is>(std::move(t))...)
, Printer2(std::get<sizeof...(Is) + Js>(std::move(t))...)
{}
public:
SeveralPrinters() = default;
SeveralPrinters(const SeveralPrinters&) = default;
SeveralPrinters(SeveralPrinters& rhs)
: SeveralPrinters(static_cast<const SeveralPrinters&>(rhs))
{}
template <typename... Args>
SeveralPrinters(Args&&... args)
: SeveralPrinters(std::make_index_sequence<Printer1::ArgsCount>{}
, std::make_index_sequence<Printer2::ArgsCount>{}
, std::forward_as_tuple(std::forward<Args>(args)...))
{}
};
struct BasicPrinter1
{
BasicPrinter1(int) {}
static constexpr ArgsCount = 1;
};
struct BasicPrinter2
{
BasicPrinter2(int*, char&) {}
static constexpr ArgsCount = 2;
};
DEMO 2
Also notice how I'm protecting the copy-constructor from being overshadowed by the forwarding-references constructor.

Related

Correct variadic pack expansion

I am working on C++20 implementation of tuple:
template<size_t INDEX, typename T>
struct wrap { [[no_unique_address]] T data {}; };
template<typename...>
class base {};
template<size_t... INDEX, typename... Ts>
class base<index_sequence<INDEX...>, Ts...> : public wrap<INDEX, Ts>... {
public:
constexpr base( const Ts &... args ) : /* !! HERE SHALL THE MAGIC COME */ {}
};
template<typename... Ts>
class tuple : public base<index_sequence_for<Ts...>, Ts...> {
public:
/* Inherit base constructors */
using base<index_sequence_for<Ts...>, Ts...>::base;
};
My question is: How to correctly implement the code in place of /* !! HERE SHALL THE MAGIC COME */ to call base, means wrap<> constructor - the wrap copy constructor taking the corresponding instance of T (expanded from base's template variadic pack Ts) hold in args?
Thanks in advance to anyone willing to help.
Parameter pack expansion also applies to member initializer lists, so you can simply do this:
template<size_t INDEX, typename T>
struct wrap { [[no_unique_address]] T data {}; };
template<typename...>
class base {};
template<size_t... INDEX, typename... Ts>
class base<std::index_sequence<INDEX...>, Ts...> : public wrap<INDEX, Ts>... {
public:
constexpr base(const Ts&... args) : wrap<INDEX, Ts>{args}... {}
};
Demo.

Simultaneous recursion over multiple parameter packs

Is it possible in C++ to simultaneously recurse over multiple (in my case two) parameter packs? How?
To give a better idea of exactly what I'm asking, I currently have a class template as follows:
template<template<typename> class C, typename... Rest>
class Inherit {};
template<template<typename> class C, typename T, typename... Rest>
class Inherit<C, T, Rest...> :
public C<T>,
public Inherit<C, Rest...>
{
};
I'm using this class template in another class which takes a parameter pack Ts to have that class inherit multiple times from a templated interface. For example:
template<typename T>
class Interface
{
...
};
template<typename... Ts>
class Example :
public Inherit<Interface, Ts...>
{
};
Now, what I would like to do is this:
template<typename T, const char* N>
class Interface
{
...
};
template<typename... Ts, const char*... Ns>
class Example :
public Inherit<Interface, Ts..., Ns...>
{
};
I need a templated Inherit class that can recurse and pick an element off of both the Ts and the Ns parameter pack at once (assuming that parameter pack Ts and Ns have the same length). I'm not versed enough in template programming to know if this is even possible?
I would argue that you don't need this Inherit class template based on the examples you gave. Here's how I'd write your first example:
template<typename T>
class Interface
{
...
};
template<typename... Ts>
class Example : public Interface<Ts>...
{
};
and your second example:
template<typename T, const char* N>
class Interface
{
};
template<typename, const char*...>
class Example;
template<typename... Ts, const char*... Ns>
class Example<std::tuple<Ts...>, Ns...> : public Interface<Ts, Ns>...
{
};
template <typename... Ts, const char*... Ns> class Example; is wrong.
You might want something like (no recursion)
template<typename T, const char* N>
class Interface
{
// ...
};
template<typename T, typename Names> class Example;
template<typename... Ts, const char*... Ns>
class Example<std::tuple<Ts...>, std::integer_sequence<const char*, Ns...>> :
public: Interface<Ts, Ns>...
{
};
Interface<Ts, Ns>... requires that both packs have the same size.

Check traits for all variadic template arguments

Background : I've created the following class C, whose constructor should take N variables of type B& :
class A;
class B
{
A* getA();
};
template<size_t N>
class C
{
public:
template<typename... Args>
inline C(Args&... args) :
member{args.getA()...}
{}
private:
std::array<A*, N> member;
};
Problem : my problem is how to constraint the variadic Args to be all of type B ?
My partial solution : I wanted to define a predicate like :
template <typename T, size_t N, typename... Args>
struct is_range_of :
std::true_type // if Args is N copies of T
std::false_type // otherwise
{};
And redefine my constructor accordingly :
template <typename... Args,
typename = typename std::enable_if<is_range_of_<B, N, Args...>::value>::type
>
inline C(Args&... args);
I've seen a possible solution on this post : https://stackoverflow.com/a/11414631, which defines a generic check_all predicate :
template <template<typename> class Trait, typename... Args>
struct check_all :
std::false_type
{};
template <template<typename> class Trait>
struct check_all<Trait> :
std::true_type
{};
template <template<typename> class Trait, typename T, typename... Args>
struct check_all<Trait, T, Args...> :
std::integral_constant<bool, Trait<T>::value && check_all<Trait, Args...>::value>
{};
So, I could write something like :
template <typename T, size_t N, typename... Args>
struct is_range_of :
std::integral_constant<bool,
sizeof...(Args) == N &&
check_all<Trait, Args...>::value
>
{};
Question 1 : I don't know how to define the Trait, because I need somehow to bind std::is_same with B as first argument. Is there any means of using the generic check_all in my case, or is the current grammar of C++ incompatible ?
Question 2 : My constructor should also accept derived classes of B (through a reference to B), is it a problem for template argument deduction ? I am afraid that if I use a predicate like std::is_base_of, I will get a different instantiation of the constructor for each set of parameters, which could increase compiled code size...
Edit : For example, I have B1 and B2 that inherits from B, I call C<2>(b1, b1) and C<2>(b1, b2) in my code, will it create two instances (of C<2>::C<B1, B1> and C<2>::C<B1, B2>) ? I want only instances of C<2>::C<B, B>.
Define all_true as
template <bool...> struct bool_pack;
template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
And rewrite your constructor to
// Check convertibility to B&; also, use the fact that getA() is non-const
template<typename... Args,
typename = std::enable_if_t<all_true<std::is_convertible<Args&, B&>{}...>>
C(Args&... args) :
member{args.getA()...}
{}
Alternatively, under C++17,
template<typename... Args,
typename = std::enable_if_t<(std::is_convertible_v<Args&, B&> && ...)>>
C(Args&... args) :
member{args.getA()...}
{}
I am afraid that if I use a predicate like std::is_base_of, I will get
a different instantiation of the constructor for each set of
parameters, which could increase compiled code size...
enable_if_t<…> will always yield the type void (with only one template argument given), so this cannot be is_base_ofs fault. However, when Args has different types, i.e. the types of the arguments are distinct, then subsequently different specializations will be instantiated. I would expect a compiler to optimize here though.
If you want the constructor to take precisely N arguments, you can use a somewhat easier method. Define
template <std::size_t, typename T>
using ignore_val = T;
And now partially specialize C as
// Unused primary template
template <size_t N, typename=std::make_index_sequence<N>> class C;
// Partial specialization
template <size_t N, std::size_t... indices>
class C<N, std::index_sequence<indices...>>
{ /* … */ };
The definition of the constructor inside the partial specialization now becomes trivial
C(ignore_val<indices, B&>... args) :
member{args.getA()...}
{}
Also, you do not have to worry about a ton of specializations anymore.
namespace detail {
template <bool...> struct bool_pack;
template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
template<class X> constexpr X implicit_cast(std::enable_if_t<true, X> x) {return x;}
};
The implicit_cast is also in Boost, the bool_pack stolen from Columbo.
// Only callable with static argument-types `B&`, uses SFINAE
template<typename... ARGS, typename = std::enable_if_t<
detail::all_true<std::is_same<B, ARGS>...>>>
C(ARGS&... args) noexcept : member{args.getA()...} {}
Option one, if it's implicitly convertible that's good enough
template<typename... ARGS, typename = std::enable_if_t<
detail::all_true<!std::is_same<
decltype(detail::implicit_cast<B&>(std::declval<ARGS&>())), ARGS&>...>>
C(ARGS&... args) noexcept(noexcept(implicit_cast<B&>(args)...))
: C(implicit_cast<B&>(args)...) {}
Option two, only if they are publicly derived from B and unambiguously convertible:
// Otherwise, convert to base and delegate
template<typename... ARGS, typename = decltype(
detail::implicit_cast<B*>(std::declval<ARGS*>())..., void())>
C(ARGS&... args) noexcept : C(implicit_cast<B&>(args)...) {}
The unnamed ctor-template-argument-type is void in any successful substitution.

C++ Variadic Template Parameter and Tuple Iteration

This question follows on from here and is to do with accessing tuple elements when the elements of the tuple are defined by means of a template.
If I have as a means of accessing the contents of a tuple:
#include <cstdint>
#include <type_traits>
#include <tuple>
namespace detail
{
template <typename T, typename... Ts> struct get_index;
template <typename T, typename... Ts>
struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename Tail, typename... Ts>
struct get_index<T, Tail, Ts...> :
std::integral_constant<std::size_t, 1 + get_index<T, Ts...>::value> {};
template <typename T>
struct get_index<T> : std::integral_constant<std::size_t, 0> {}; // Not found
template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>& t) noexcept
-> typename std::enable_if<N < sizeof...(Ts), decltype(&std::get<N < sizeof...(Ts) ? N : 0>(t))>::type
{
return &std::get<N>(t);
}
template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>&) noexcept
-> typename std::enable_if<sizeof...(Ts) <= N, nullptr_t>::type
{
return nullptr;
}
}
I want to access the tuple elements here, but where each tuple element is created by means of a template. Thus:
class BaseElement {
public:
virtual int polymorphicFunction() {return 0;};
};
template <uint32_t exampleParameter = 1>
class DerivedElement1 : public BaseElement {
public:
DerivedElement1() : i(exampleParameter) {}
virtual int polymorphicFunction() {return 1;};
uint32_t i; /// just used as a placeholder to demo use of parameter
}
template <uint32_t exampleParameter = 2>
class DerivedElement2 : public BaseElement {
public:
DerivedElement2() : i(exampleParameter) {}
virtual int polymorphicFunction() {return 2;};
uint64_t i; /// just used as a placeholder to demo use of parameter (class is different to DE1)
}
template<typename... systems> // systems will always be of derived class of BaseElement
class System {
System() : subsystems(systems{}...),
pd1(detail::safe_get<detail::get_index<DerivedElement1, systems...>::value>(subSystems)),
pd2(detail::safe_get<detail::get_index<DerivedElement2, systems...>::value>(subSystems))
{} // all variadic elements stored in tuple
const std::tuple<systems...> subSystems;
DerivedElement1<> *pd1;
DerivedElement2<> *pd2;
};
pd1 & pd2 should be set to point to the respective derived elements if they exist when specified in the declaration of System, otherwise they should be set to null.
This works when I do:
System<DerivedElement1<>, DerivedElement2<>> sys; // sys.pd1 points to DerivedElement1<> element of tuple, sys.pd2 points to DerivedElement2<> within tuple
But if I supply a variable to the declaration of System, pd1 & pd2 are both set to nullptr.
System<DerivedElement1<5>, DerivedElement2<6>> sys; // sys.pd1 == nullptr, sys.pd2 == nullptr
How can I get pd1 & pd2 to point to the correct tuple elements please?
Edit to try to be more clear:
Different types, derived from a common class, are stored in a tuple (e.g. DerivedElement1<>, DerivedElement2<6>). I have within the storage class pointers that should point to the derived class elements of the tuple. The set pointer code I have works when I use no template parameters, (i.e. DerivedElement1<> in the example above), but does not when I use a template parameter (e.g. DerivedElement1<5>).
So you need instead of get_index:
namespace detail
{
template <template<typename> class Pred, typename... Ts> struct get_index_if;
template <template<typename> class Pred, typename T, typename... Ts>
struct get_index_if<Pred, T, Ts...> :
std::integral_constant<
std::size_t,
Pred<T>::value ? 0 : 1 + get_index_if<Pred, Ts...>::value>
{};
template <template<typename> class Pred>
struct get_index_if<Pred> : std::integral_constant<std::size_t, 0> {}; // Not found
}
A predicate for your types for get_index_if:
template <typename T> struct is_a_Derived1 : std::false_type {};
template <std::uint32_t N> struct is_a_Derived1<DerivedElement1<N>> : std::true_type {};
template <typename T> struct is_a_Derived2 : std::false_type {};
template <std::uint32_t N> struct is_a_Derived2<DerivedElement2<N>> : std::true_type {};
And finally:
// helper for trailing return type... until C++14
#define Return(Ret) decltype Ret { return Ret; }
template <typename... systems>
class System {
const std::tuple<systems...> subSystems;
public:
constexpr System() : subSystems() {}
auto getDerivedElement1()
-> Return((detail::safe_get<detail::get_index_if<is_a_Derived1, systems...>::value>(subSystems)))
auto getDerivedElement2()
-> Return((detail::safe_get<detail::get_index_if<is_a_Derived2, systems...>::value>(subSystems)))
};
Note: As DerivedElement1<N1> and DerivedElement1<N2> are different types (for N1 != N2), the only possible member type would be he base class.
Here you have getter methods with correct type (or nullptr_t when element is absent).
Note: the given predicate doesn't support derived class of DerivedElement1<N>.

Heterogenous storage of variadic class parameter member variables

I have a variadic class template that is used to create a top-level class for a variable number of classes. Each class that is to go in the top-level class is derived from a base class, as there is common functionality for them. I don't know the best way to store the derived classes in the parent class, but still be able to access the full functionality of the derived class.
If I store the variadic args in a vector, they'll all be stored as a base class and I can't access the derived functionality. If I store them in a tuple, I can't work out how to access the functions by derived type. If I try to access them as discussed here on SO then make_unique isn't available (C++14?).
So, I want to do the following:
class BaseElement {
public:
virtual int polymorphicFunction() {return 0;};
};
class DerivedElement1 : public BaseElement {
public:
virtual int polymorphicFunction() {return 1;};
}
class DerivedElement2 : public BaseElement {
public:
virtual int polymorphicFunction() {return 2;};
}
template<typename... systems> // systems will always be of derived class of BaseElement
class System {
System() : subsystems(systems{}...) {} ; // all variadic elements stored in tuple
// tuple used below, the system elements don't need to be stored in a container, I just want to access them
// I'd be happy to use a vector or access them directly as a member variable
// provided that I can access the derived class. I can't use RTTI.
const std::tuple<systems...> subSystems;
// pointer or reference, I don't mind, but pd1/2 will always exist,
// (but perhaps be NULL), even if there is no derived element passed to the template parameter
DerivedElement1 *pd1;
DerivedElement2 *pd2;
};
//Desired usage
System<DerivedElement1> sys; // sys->pd1 == &derivedElement1WithinTuple, sys->pd2 == NULL
System<DerivedElement2> sys; // sys->pd2 == &derivedElement2WithinTuple, sys->pd2 == NULL
System<DerivedElement1, DerivedElement2> sys; // sys->pd1 == &derivedElement1WithinTuple, sys->pd1 == &derivedElement1WithinTuple
Does anyone have any suggestions as to how I might achieve this please?
With:
#include <cstdint>
#include <type_traits>
#include <tuple>
namespace detail
{
template <typename T, typename... Ts> struct get_index;
template <typename T, typename... Ts>
struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename Tail, typename... Ts>
struct get_index<T, Tail, Ts...> :
std::integral_constant<std::size_t, 1 + get_index<T, Ts...>::value> {};
template <typename T>
struct get_index<T> : std::integral_constant<std::size_t, 0> {}; // Not found
template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>& t) noexcept
-> typename std::enable_if<N < sizeof...(Ts), decltype(&std::get<N < sizeof...(Ts) ? N : 0>(t))>::type
{
return &std::get<N>(t);
}
template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>&) noexcept
-> typename std::enable_if<sizeof...(Ts) <= N, nullptr_t>::type
{
return nullptr;
}
}
You may have:
template <typename... systems>
class System {
public:
constexpr System() :
subSystems(),
pd1(detail::safe_get<detail::get_index<DerivedElement1, systems...>::value>(subSystems)),
pd2(detail::safe_get<detail::get_index<DerivedElement2, systems...>::value>(subSystems))
{}
const std::tuple<systems...> subSystems;
const DerivedElement1 *pd1;
const DerivedElement2 *pd2;
};