Infinite recursion in templates - c++

Suppose I have a proxy class called List which is nothing more than a holder for a bunch of typenames:
template<typename... items> class List {
constexpr size_t SizeOf = /*Magic code that determines the length*/;
};
And suppose I have another class which is supposed to take to Lists and output a version where the smaller one is padded with null_ts:
template<class flist,class slist>
class Pad{
typedef /*Undertermined*/ Flist;
typedef /*Undertermined*/ Slist;
};
The only real problem is breaking the recursion....normally in template recursion you just specialize and then you can end it.
Here is a little different because there is no way (at least that I can see) to tell by the template deceleration the difference between the two list.
I tried to use a std::conditional to end the cycle but that does not work.
Here is an example:
template<int x>
class Mine{
typedef std::conditional<x == 12, Mine<x>::value, Mine<x+1>::value> value;
};
Even though I have the x==12 condition it still needs (or wants) to flush out the Mine<x+1>::value.
So what is the general strategy for this scenario?

This is a non-recursive solution for the implementation of Pad, but it also shows how you can use partial specialization to avoid instantiating templates based on a condition:
#include <cstddef>
#include <utility>
#include <type_traits>
#include <iostream>
template<class... Ts> struct List { static constexpr std::size_t size = sizeof...(Ts); };
struct null_t { };
template<std::size_t> using make_null_t = null_t;
template<class, class> struct pad_imp2;
template<class... Ts, std::size_t... Is> struct pad_imp2<List<Ts...>, std::index_sequence<Is...>>
{
using type = List<Ts..., make_null_t<Is>...>;
};
// Don't instantiate make_index_sequence if L::size >= S.
template<class, std::size_t, bool> struct pad_imp { using type = void; };
template<class L, std::size_t S> struct pad_imp<L, S, true>
{
using type = typename pad_imp2<L, std::make_index_sequence<S - L::size>>::type;
};
template<class L, std::size_t S> using pad_hlp = typename pad_imp<L, S, L::size < S>::type;
template<class L1, class L2> struct Pad
{
using L1_padded = std::conditional_t<L1::size < L2::size, pad_hlp<L1, L2::size>, L1>;
using L2_padded = std::conditional_t<L2::size < L1::size, pad_hlp<L2, L1::size>, L2>;
};
int main()
{
using list1 = List<short, int, long>;
using list2 = List<double>;
std::cout << std::is_same<Pad<list1, list2>::L1_padded, list1>::value << '\n';
std::cout << std::is_same<Pad<list1, list2>::L2_padded, List<double, null_t, null_t>>::value << '\n';
}
The padding is done by generating a list of null_ts using the dummy make_null_t alias template and a pack of indices of the right size.

One way to stop the recursion in your second example is to use boost.mpl. For example,
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/integral_c.hpp>
template<int x>
struct Mine {
using type = typename boost::mpl::eval_if<boost::mpl::bool_<x == 12>,
boost::mpl::integral_c<short, 12>,
Mine<x+1>
>::type;
};
In the above example, it will always give you 12 as a value, regardless of the argument (as long as it is less or equal to 12).

As I understood you need to break recursion at Mine structure. If that is right, you can use full template specialization of this struct (for implementing terminal case of recursion). It looks like that:
template<>
struct Mine<123456>{
// It is struct represents end of recursion
};
It is simple example of usage this approach for computing factorial:
#include <iostream>
template <int N>
struct Factorial
{
static const int fact = N * Factorial<N - 1>::fact;
};
template <>
struct Factorial<0>
{
static const int fact = 1;
};
int main()
{
std::cout << Factorial<1>::fact << std::endl;
std::cout << Factorial<3>::fact << std::endl;
return 0;
}

Related

How to return multi- dimensional-vector of given dimension and type?

Is it possible in modern c++ to write a function that, given a number n and a type, return a n-dimensional vector type.
1,float -> return std::vector<float>
2,float -> return std::vector<std::vector<float>>
and so on...
Here is a compile time approach using template specialization. We apply std::vector<> recursively until we reach the specialization for N == 0, where the final type is set to T:
#include <type_traits>
#include <vector>
template<std::size_t N, typename T>
struct recursive_vector {
using type = std::vector<typename recursive_vector<N - 1, T>::type>;
};
template<typename T>
struct recursive_vector<0, T> {
using type = T;
};
template<std::size_t N, typename T>
using vec = recursive_vector<N, T>::type;
so vec<3, float> becomes vector<vector<vector<float>>>:
int main() {
vec<3, float> v;
using std::vector;
static_assert(std::is_same_v<decltype(v), vector<vector<vector<float>>>>);
}
Try out the code, here.
Is it possible in modern C++ to write a function that given a number n and a type return a n-dimensional vector type?
Compile time
If n is known at compile time, the job easy, which is already given in the other answer. Alternatively, you could also do:
#include <vector>
template<typename T, std::size_t N>
struct vec : public vec<std::vector<T>, N - 1u> {};
template<typename T> struct vec<T, 0u> { using type = T; };
template<typename T, std::size_t N> using vec_t = typename vec<T, N>::type;
Now vec_t<float, 5u> means std::vector<std::vector<std::vector<std::vector<std::vector<float>>>>>
(See a live demo in godbolt.org)
Run time
When n is run time depended, one possible solution is to wrap the possible multidimensional vectors types to std::variant (Since c++17).
Following is an example code.
#include <vector>
#include <variant> // std::variant
// type aliases for the multi-dim vectors
template<typename T> using Vec1D = std::vector<T>;
template<typename T> using Vec2D = Vec1D<Vec1D<T>>;
template<typename T> using Vec3D = Vec1D<Vec2D<T>>;
// ... so on (hope that you wouldn't need more than 4 or 5!)
template<typename T>
using VecVariants = std::variant<Vec1D<T>, Vec2D<T>, Vec3D<T>/*, so on ...*/>;
template<typename T> auto getVector_of(const std::size_t n)
{
if (n == 1) return VecVariants<T>{Vec1D<T>{}};
if (n == 2) return VecVariants<T>{Vec2D<T>{}};
if (n == 3) return VecVariants<T>{Vec3D<T>{}};
// ... so on
return VecVariants<T>{Vec3D<T>{}}; // some default return!
}
template<typename T> void doSomething(const VecVariants<T>& vec)
{
std::visit([](auto&& arg) {
using Type = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<Type, Vec1D<T>>)
std::cout << "... do something with Vec1D\n";
else if constexpr (std::is_same_v<Type, Vec2D<T>>)
std::cout << "... do something with Vec2D\n";
else if constexpr (std::is_same_v<Type, Vec3D<T>>)
std::cout << "... do something with Vec3D\n";
// .... so on
else
std::cout << "... default!\n";
}, vec);
}
Now you can pass run time n
int main()
{
std::size_t n{ 5 };
while (n)
doSomething(getVector_of<float>(n--)); // n must be 0u < n <= MAX_n you defined!
}
(See a live demo in godbolt.org)

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.

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

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 << ")";
}

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?

Variadic templates with constants

I'm doing some experimenting with metaprogramming and variadic templates, and I'm having trouble with some confusing behaviour. I've stripped it down to a minimum working example, but essentially I want to keep track of how many recursive calls I'm making. I want to do this by making the first template parameter an integer, while the second template parameter is a variadic list. In simplest form it looks like this:
template<typename... List>
struct initial_call{
static const int val = next_call<0, List...>::val;
};
template<int D, typename... List>
struct next_call {
static const int val = D;
};
So ignoring the fact that this code is pointless, it doesn't compile on VS2013, claiming "unexpected type 'List", on the line inside the definition of initial_call. Without the integer in front, it works fine. So is there a way to combine variadic templates with integer template parameters?
You might want something like this (counting the number of types):
#include <iostream>
// More than one type: Increment size and consume.
template<size_t N, typename T, typename... List>
struct calculate_list_size {
static const size_t value = calculate_list_size<N + 1, List...>::value;
};
// Last type: Increment size and terminate.
template<size_t N, typename T>
struct calculate_list_size<N, T> {
static const size_t value = N + 1;
};
// Forward to calculate_list_size.
template<typename... List>
struct list_size {
static const size_t value = calculate_list_size<0, List...>::value;
};
// Empty list
template<>
struct list_size<> {
static const size_t value = 0;
};
int main()
{
std::cout << list_size<char, short, int>::value << '\n';
std::cout << list_size<>::value << '\n';
}