How pass the same struct with different template argument as parameter pack - c++

Thanks to SO guys I resolved one of my problem:
Create a tuple with variatic type wrapped
But I realized after that, I still have a problem that I can't solve.
So now I have :
template < typename T,
size_t Size >
struct Metadata {
using type = T;
std::bitset<Size> bitset;
};
template <class... Ts>
constexpr auto make_metadata()
{
constexpr size_t N = sizeof...(Ts);
return std::make_tuple(Metadata<Ts, N>{0}...);
}
I intent to use it "like" that :
constexpr auto result = make_metadata<Foo1, Foo2, Foo3>({0}, {0}, {0});
And according to Jarod42 comment, I think I'll need 2 functions.
But how I can pass the arguments to the function and then to the tuple?
And I wonder how do that but without force to pass each arguments for each Ts, if they are not present I'll just put a default value (2 questions).

this may be what you want, I am not sure. (since you never show where the arguments to be used)
#include <tuple>
#include <bitset>
#include <iostream>
struct A{int value;};
struct B{int value;};
struct C{int value;};
template <typename T,int Size>
struct Metadata{
using type = T;
T value;
std::bitset<Size> bitset;
};
template <typename...Ts,typename...Args>
constexpr auto make_metadata(Args... args)
{
constexpr auto N = sizeof...(Ts);
return std::make_tuple(Metadata<Ts, N>{args,0}...);
}
int main(){
auto data = make_metadata<A,B,C>(1,2,3);
std::cout << "(" << std::get<0>(data).value.value
<< ", " << std::get<1>(data).value.value
<< ", " << std::get<2>(data).value.value << ")";
}

Related

count std::optional types in variadic template tuple

I've got a parameter pack saved as a tuple in some function traits struct.
How can I find out, how many of those parameters are std::optional types?
I tried to write a function to check each argument with a fold expression, but this doesn't work as I only pass a single template type which is the tuple itself.
void foo1(){}
void foo2(int,float){}
void foo3(int, std::optional<int>, float, std::optional<int>){}
void foo4(int, std::optional<int>, bool){}
template<typename R, typename... TArgs>
struct ftraits<R(TArgs...)>
{
using ret = R;
using args = std::tuple<TArgs...>;
};
template<typename T>
struct is_optional : std::false_type
{
};
template<typename T>
struct is_optional<std::optional<T>> : std::true_type
{
};
template<typename... Ts>
constexpr auto optional_count() -> std::size_t
{
// doesn't work since Ts is a single parameter with std::tuple<...>
return (0 + ... + (is_optional<Ts>::value ? 1 : 0));
}
int main() {
using t1 = typename ftraits<decltype(foo1)>::args;
std::cout << optional_count<t1>() << std::endl; // should print 0
using t2 = typename ftraits<decltype(foo2)>::args;
std::cout << optional_count<t2>() << std::endl; // should print 0
using t3 = typename ftraits<decltype(foo3)>::args;
std::cout << optional_count<t3>() << std::endl; // should print 2
using t4 = typename ftraits<decltype(foo4)>::args;
std::cout << optional_count<t4>() << std::endl; // should print 1
}
You can use template partial specialization to get element types of the tuple and reuse the fold-expression
template<typename>
struct optional_count_impl;
template<typename... Ts>
struct optional_count_impl<std::tuple<Ts...>> {
constexpr static std::size_t count =
(0 + ... + (is_optional<Ts>::value ? 1 : 0));
};
template<typename Tuple>
constexpr auto optional_count() -> std::size_t {
return optional_count_impl<Tuple>::count;
}
Demo
You can get the size of the tuple using std::tuple_size, then iterate over all its members using a recursive template. In that template, you can pretend to construct an instance of the tuple using std::declval, get the value at the current index using std::get, and then finally get the type of that value using decltype.
Example implementation:
#include <optional>
#include <tuple>
#include <utility>
template<typename T>
struct is_optional : std::false_type {};
template<typename T>
struct is_optional<std::optional<T>> : std::true_type {};
template<typename Tuple, size_t i>
constexpr size_t optional_count_impl() {
size_t val = is_optional<std::remove_reference_t<decltype(std::get<i>(std::declval<Tuple>()))>>::value ? 1 : 0;
if constexpr (i) {
val += optional_count_impl<Tuple, i - 1>();
}
return val;
}
template<typename Tuple>
constexpr size_t optional_count() {
const size_t tuple_size = std::tuple_size<Tuple>::value;
if constexpr (tuple_size == 0) {
return 0;
} else {
return optional_count_impl<Tuple, tuple_size - 1>();
}
}
using Tup1 = std::tuple<int, int, std::optional<size_t>, bool, std::optional<bool>, std::optional<std::optional<int>>>;
int main() {
return optional_count<Tup1>();
}

Accepting std::array of char of any size as non type template parameter

This is probably a weird use case, but I am trying to hack around the fact string literals can not be used as arguments to templates using std::array<char, N> as non template type parameter.
This works but with extreme limitation that all strings must be of same length(I could use MAX_STR_LEN=100 or whatever and make all arrays that size, but that feels ugly...).
Is there a way to make this code work so that different size std::arrays can be accepted as template parameter?
#include <iostream>
#include <array>
#include <tuple>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/tuple.hpp>
// I wish that this 6 is not fixed... but IDK how to fix it, maybe concept(IDK if concepts can be used as "types" on NTTP.
template <typename Type, std::array<char, 6> val_val>
struct TypeToValues
{
using type = Type;
static constexpr const char* val = val_val.data();
};
template <std::size_t Sz, std::size_t... Is>
constexpr std::array<char, Sz>
arrayify(const char (&arr)[Sz], std::index_sequence<Is...>)
{
return {{arr[Is]...}};
}
template <std::size_t Sz>
constexpr std::array<char, Sz> arrayify(const char (&arr)[Sz])
{
return arrayify(arr, std::make_index_sequence<Sz>());
}
struct HelloType{
};
struct YoloType{
};
int main(){
std::tuple<
TypeToValues<HelloType, arrayify("Hello")>,
TypeToValues<YoloType, arrayify("Yolo!")>> mapping;
boost::mp11::tuple_for_each(mapping, []<typename T>(const T&){
if constexpr(std::is_same_v<typename T::type, HelloType>){
std::cout << "HelloType says: " << T::val << std::endl;;
}
if constexpr(std::is_same_v<typename T::type, YoloType>){
std::cout << "YoloType says: " << T::val << std::endl;;
}
});
}
Sure, why not use a requires requires clause?
template <typename Type, auto val_val>
requires requires { { val_val.data() } -> std::same_as<char const*>; }
struct TypeToValues
{
// ...
Example.
You could also write a constraint that only specifically std::array<char, N> satisfy:
template<class> constexpr bool is_array_of_char_v = false;
template<unsigned N> constexpr bool is_array_of_char_v<std::array<char, N>> = true;
template<class T> concept ArrayOfChar = requires { is_array_of_char_v<T>; };
template <typename Type, ArrayOfChar auto val_val>
struct TypeToValues
{
// ...
But that feels excessively restrictive; you'll want to accept static string types in future.

Want kind of constexpr switch case on type

I am currently doing this trick to have a cstring based on a type:
template<class ListT> static char constexpr * GetNameOfList(void)
{
return
std::conditional<
std::is_same<ListT, LicencesList>::value, "licences",
std::conditional<
std::is_same<ListT, BundlesList>::value, "bundles",
std::conditional<
std::is_same<ListT, ProductsList>::value, "products",
std::conditional<
std::is_same<ListT, UsersList>::value, "users",
nullptr
>
>
>
>;
}
But this code is not very good-looking, and if we want to check more types, this could be unreadable. Is it a way to do the same thing as if there were a switch case block?
Actually, the code is more complicated than that, because std::conditional need some type, so we need some class to do the trick:
struct LicenceName { static char constexpr * value = "licences"; };
for example.
I think it would be easier using template specialization
Example code:
#include <iostream>
struct A{};
struct B{};
struct C{};
struct D{};
template<typename T> constexpr const char* GetNameOfList();
//here you may want to make it return nullptr by default
template<>constexpr const char* GetNameOfList<A>(){return "A";}
template<>constexpr const char* GetNameOfList<B>(){return "B";}
template<>constexpr const char* GetNameOfList<C>(){return "C";}
int main(){
std::cout << GetNameOfList<A>() << '\n';
std::cout << GetNameOfList<B>() << '\n';
std::cout << GetNameOfList<C>() << '\n';
//std::cout << GetNameOfList<D>() << '\n'; //compile error here
}
You don't need to resort to metaprogramming, plain ifs work just fine:
template<class ListT>
constexpr char const *GetNameOfList() {
if(std::is_same<ListT, A>::value) return "A";
if(std::is_same<ListT, B>::value) return "B";
if(std::is_same<ListT, C>::value) return "C";
if(std::is_same<ListT, D>::value) return "D";
return nullptr;
}
See it live on Coliru
You could create constexpr array of strings plus tuple of list types to create mapping list type -> index -> name (if you need the mapping index -> types containing strings just use tuple instead of array). c++17 approach could look as follows:
#include <type_traits>
#include <tuple>
#include <utility>
#include <iostream>
struct LicencesList{};
struct BundlesList{};
struct ProductsList{};
struct UsersList{};
using ListTypes = std::tuple<LicencesList, BundlesList, ProductsList, UsersList>;
constexpr const char *NameList[] = {"licences", "bundles", "products", "users"};
template <class Tup, class, class = std::make_index_sequence<std::tuple_size<Tup>::value>>
struct index_of;
template <class Tup, class T, std::size_t... Is>
struct index_of<Tup, T, std::index_sequence<Is...>> {
static constexpr std::size_t value = ((std::is_same<std::tuple_element_t<Is, Tup>, T>::value * Is) + ...);
};
template<class ListT> static const char constexpr * GetNameOfList(void) {
return NameList[index_of<ListTypes, ListT>::value];
}
int main() {
constexpr const char *value = GetNameOfList<BundlesList>();
std::cout << value << std::endl;
}
[live demo]
If you want to maintain c++11 compatibility the approach would be just a little bit longer (I used here Casey's answer to implement index_of structure):
#include <type_traits>
#include <tuple>
#include <iostream>
struct LicencesList{};
struct BundlesList{};
struct ProductsList{};
struct UsersList{};
using ListTypes = std::tuple<LicencesList, BundlesList, ProductsList, UsersList>;
constexpr const char *NameList[] = {"licences", "bundles", "products", "users"};
template <class Tuple, class T>
struct index_of;
template <class T, class... Types>
struct index_of<std::tuple<T, Types...>, T> {
static const std::size_t value = 0;
};
template <class T, class U, class... Types>
struct index_of<std::tuple<U, Types...>, T> {
static const std::size_t value = 1 + index_of<std::tuple<Types...>, T>::value;
};
template<class ListT> static const char constexpr * GetNameOfList(void) {
return NameList[index_of<ListTypes, ListT>::value];
}
int main() {
constexpr const char *value = GetNameOfList<BundlesList>();
std::cout << value << std::endl;
}
[live demo]

calculating data compile time with template metaprogramming

Suppose we have code like this. It works well and pre-calculate first 5 Fibonacci numbers.
#include <iostream>
template <int T>
struct fib;
template <>
struct fib<0>{
constexpr static int value = 1;
};
template <>
struct fib<1>{
constexpr static int value = 1;
};
template <int I>
struct fib{
constexpr static int value = fib<I - 1>::value + fib<I - 2>::value;
};
int main(){
std::cout << fib<0>::value << std::endl;
std::cout << fib<1>::value << std::endl;
std::cout << fib<2>::value << std::endl;
std::cout << fib<3>::value << std::endl;
std::cout << fib<4>::value << std::endl;
std::cout << fib<5>::value << std::endl;
}
However there is "small" problem with it.
What if we need to use this for values, that are not known at compile time?
For few values we can do this:
const int max = 5;
int getData(){
return 5; // return value between 0 and max.
}
int something(){
switch(getData()){
case 0: return fib<0>::value;
case 1: return fib<1>::value;
case 2: return fib<2>::value;
case 3: return fib<3>::value;
case 4: return fib<4>::value;
case 5: return fib<5>::value;
}
}
This will works OK for 5 values, but what if we have 150 or 300?
Is not really serious to change the code with 300 rows...
What could be the workaround here?
If you need to use a value at runtime that isn't known at compile time, you can't compute it at compile time. Obvious.
But... if you can impose a top value to values needed, you can compute all values (from zero to top) at compile time and store them in an std::array.
In the following example I have modified your fib structs (to use a std::size_t index and a template type (with default unsigned long) for the value) and I have added a templated struct fibVals that contain an std::array that is initialized using fib<n>::value
The following main() show that is possible to define a constexpr fibvals<N> (with N == 20 in the example) to compute (at compile time) all fib<n> values in range [0,N[.
#include <array>
#include <utility>
#include <iostream>
template <std::size_t, typename T = unsigned long>
struct fib;
template <typename T>
struct fib<0U, T>
{ constexpr static T value { T(1) }; };
template <typename T>
struct fib<1U, T>
{ constexpr static T value { T(1) }; };
template <std::size_t I, typename T>
struct fib
{ constexpr static T value { fib<I-1U>::value + fib<I-2U>::value }; };
template <std::size_t I, typename T = unsigned long>
struct fibVals
{
const std::array<T, I> vals;
template <std::size_t ... Is>
constexpr fibVals ( std::index_sequence<Is...> const & )
: vals { { fib<Is, T>::value ... } }
{ }
constexpr fibVals () : fibVals { std::make_index_sequence<I> { } }
{ }
};
int main()
{
constexpr fibVals<20> fv;
for ( auto ui = 0U ; ui < fv.vals.size() ; ++ui )
std::cout << "fib(" << ui << ") = " << fv.vals[ui] << std::endl;
}
Unfortunately this example use std::make_index_sequence<I> and std::index_sequence<Is...> that are C++14 features.
If you want implement struct fibVals in C++11, you can implement the following structs struct indexSeq and struct indexSeqHelper, to substitute std::index_sequence<Is...> and std::make_index_sequence<I>
template <std::size_t ...>
struct indexSeq
{ };
template <std::size_t N, std::size_t ... Next>
struct indexSeqHelper
{ using type = typename indexSeqHelper<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct indexSeqHelper<0U, Next ... >
{ using type = indexSeq<Next ... >; };
and implement fibVals constructors as follows
template <std::size_t ... Is>
constexpr fibVals ( indexSeq<Is...> const & )
: vals { { fib<Is, T>::value ... } }
{ }
constexpr fibVals () : fibVals { typename indexSeqHelper<I>::type { } }
{ }
Templates are evaluated at compile time, so there is no solution with templates that works at runtime.
You can make a constexpr function, which may be evaluated at compile time, depending on the value passed. Obviously, a runtime value may not be computed at compile time, as it is not known at compile time.

Associating an array with a variadic template

I'm now learning a little about templates and templates in C++11, C++14 and C++1z. I'm trying to write a variadic class template with an inside class that will associate an int to every template argument - and have a constexpr method that returns its array representation.
Let's say that I have ensured that the template cannot receive two of the same type as an argument. I was thinking about doing it somewhat like this:
template <typename... Types>
struct MyVariadicTemplate {
//we know that all types in Types... are different
template <int... Values>
struct MyInnerTemplate {
//I need to make sure that sizeof...(Values) == sizeof...(Types)
constexpr std::array<int, sizeof...(Values)> to_array() {
std::array<int, sizeof...(Values)> result = {Values...};
return result;
// this is only valid since C++14, as far as I know
}
};
};
this code should be valid (if it's not, I'd love to know why). Now, I'd like to add another inner template:
template <typedef Type>
struct AnotherInnerTemplate {};
that has a public typedef, which represents MyInnerTemplate with one on the position of Type in Types... and zeros elsewhere - and here I'm lost. I don't know how to proceed
I would appreciate any hint on how that can be done - and if I'm heading towards the wrong direction, I hope somebody can give me a hint on how to do that.
I think what you're looking for is something like this.
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
template <typename NeedleT, typename... HaystackTs>
constexpr auto get_type_index_mask() noexcept
{
constexpr auto N = sizeof...(HaystackTs);
return std::array<bool, N> {
(std::is_same<NeedleT, HaystackTs>::value)...
};
}
template <typename T, std::size_t N>
constexpr std::size_t ffs(const std::array<T, N>& array) noexcept
{
for (auto i = std::size_t {}; i < N; ++i)
{
if (array[i])
return i;
}
return N;
}
int
main()
{
const auto mask = get_type_index_mask<float, bool, int, float, double, char>();
for (const auto& bit : mask)
std::cout << bit;
std::cout << "\n";
std::cout << "float has index " << ffs(mask) << "\n";
}
Output:
00100
float has index 2
The magic happens in the parameter pack expansion
(std::is_same<NeedleT, HaystackTs>::value)...
where you test each type in HaystackTs against NeedleT. You might want to apply std::decay to either type if you want to consider, say, const int and int the same type.
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
Full:
template <class... Types> struct My {
template <int... Values> struct Inner {
constexpr std::array<int, sizeof...(Values)> to_array() {
return std::array<int, sizeof...(Values)>{Values...};
}
};
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
};
auto main() -> int {
My<int, float, char>::Another<int>::Type s;
auto a = s.to_array();
for (auto e : a) {
cout << e << " ";
}
cout << endl;
return 0;
}
prints:
1 0 0
Is this what you want?