specialization of variadic templates with class templates - c++

Here's an issue I ran across while playing with variadic templates. I have some code that uses specialization to count "interesting" types in a parameter pack like so:
template<typename... _Pp>
struct count;
template<>
struct count<>
{
static const int value = 0;
};
// ignore uninteresting types
template<typename _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = count<_Rest...>::value;
};
// add 1 for a pointer
template<typename _First, typename... _Rest>
struct count<_First*, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for a reference
template<typename _First, typename... _Rest>
struct count<_First&, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
// add 1 for an int
template<typename... _Rest>
struct count<int, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
This code works fine, but I run into problems if I want to use the same approach to count class templates:
// add 1 for a vector
template<typename... _Rest>
struct count<vector, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
The above code fails to compile, error is "expected a type, got 'vector'" on the line beginning with "struct count". I'm also unable to something simpler, all class templates accepting a single argument:
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename... _Rest>
struct count<_First, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
}
This code also fails to compile, complaining of "expected a type, got '_First'" once again on the line beginning with "struct count". Is someone familiar with a way to accomplish this goal using this approach (i.e. some modification that I can make to one or both of the specializations that will get them to compile and perform the desired calculation at compile time)?
EDIT:
I want the parameter pack for vector to be unbound, similar to the following code for a simple container wrapper with variadic template-template parameters that also specializes on std::vector:
// pass a container as a parameter using variadic template-template
parameter
template<typename _Tp, template<typename...> class _C>
struct success
{
// not specialized for any container
static const bool is_specialized = false;
// data member of container type
_C<_Tp> c_;
};
// partial specialization of above for std::vector
template<typename _Tp>
struct success<_Tp, std::vector>
{
// specialized for vector
static const bool is_specialized = true;
// again, data member of container type
std::vector<_Tp> c_;
};
EDIT
Seems like the final answer is that what I want to do can't be accomplished, but I have found a way to reframe the problem so that I cans solve it. Many thanks to those who helped.

If I understand correctly what you want... yes, you can create a templated struct that can count "class templates", so you can write something like
count<std::vector, std::map, std::set, std::pair>::value
but you can't mix class templates and simple typenames, so you can't write something like
count<std::vector, int &, float, std::set>::value
The problem is that if you define
template <typename... _Pp>
struct count;
you can pass std::vector<int> to it, because std::vector<int> is a typename, but you can't pass std::vector to it because std::vector isn't a typename; it's a template<typename...> class (or template template) that it's a total different things.
You can write something like the following struct countC
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
The following is a working complete example where I've rewritten your struct count as struct countT for count selected types, I've added a struct countC to count selected "class templates" and I've added a struct countV to count selected values of a fixed typename.
#include <map>
#include <set>
#include <vector>
#include <utility>
#include <iostream>
// countC for templates
template <template<typename...> class ...>
struct countC;
template <>
struct countC<>
{ static const int value = 0; };
// ignore uninteresting templates
template<template<typename...> class F, template<typename...> class ... R>
struct countC<F, R...>
{ static const int value = countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::vector, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::map, R...>
{ static const int value = 1 + countC<R...>::value; };
template <template<typename...> class ... R>
struct countC<std::pair, R...>
{ static const int value = 1 + countC<R...>::value; };
// countV for for values of a fixed type
template <typename T, T ... v>
struct countV;
template <typename T>
struct countV<T>
{ static const int value = 0; };
// ignore uninteresting values
template <typename T, T f, T ... r>
struct countV<T, f, r...>
{ static const int value = countV<T, r...>::value; };
// count only int odd values
template <int f, int ... r>
struct countV<int, f, r...>
{ static const int value = (f % 2) + countV<int, r...>::value; };
// countT for typenames
template <typename...>
struct countT;
template <>
struct countT<>
{ static const int value = 0; };
// ignore uninteresting types
template <typename F, typename ... R>
struct countT<F, R...>
{ static const int value = countT<R...>::value; };
template <typename F, typename ... R>
struct countT<F*, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename F, typename ... R>
struct countT<F&, R...>
{ static const int value = 1 + countT<R...>::value; };
template<typename ... R>
struct countT<int, R...>
{ static const int value = 1 + countT<R...>::value; };
int main()
{
std::cout << "countC vector + map + set + pair = "
<< countC<std::vector, std::map, std::set, std::pair>::value
<< std::endl;
std::cout << "countT int + float + bool* + double& + bool + int& = "
<< countT<int, float, bool*, double&, bool, int&>::value
<< std::endl;
std::cout << "countV int, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<int, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
std::cout << "countV long, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = "
<< countV<long, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value
<< std::endl;
return 0;
}
p.s.: sorry for my bad English.

How about something like this?
// add 1 for a vector
template<typename... _Rest, typename T>
struct count<vector<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
And this?
// add 1 for a class template with 1 type parameter
template<template<typename> class _First, typename T, typename... _Rest>
struct count<_First<T>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};

It should be:
template<typename... _Rest, typename... T>
struct count<std::vector<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
Generic version:
template<template<typename...> class C, typename... _Rest, typename... T>
struct count<C<T...>, _Rest...>
{
static const int value = 1 + count<_Rest...>::value;
};
Variadic pack matters.

Related

Template Metaprogramming to calculate Fibonacci

Recently in a job interview I was asked to give the result of 100th element of a 3rd-class Fibonacci sequence(Fib(n)=Fib(n-1)+Fib(n-2)+Fib(n-3). I finished by Mathematical Induction and constructing a class to present numbers larger than long long. Then I was asked to implement it via template meta-programming. The problem is that the result will exceed the range of long long and I don't know how to fix this. Here is my code using template meta-programming.
template<long long num>
struct fib
{
enum { result = fib<num - 1>::result + fib<num - 2>::result + fib<num - 3>::result};
};
template<>
struct fib<0>
{
enum { result = 1 };
};
template<>
struct fib<1>
{
enum { result = 1 };
};
template<>
struct fib<2>
{
enum { result = 2 };
};
template<>
struct fib<3>
{
enum { result = 4 };
};
int main()
{
cout << fib<100>::result << endl;
return 0;
}
A possible implementation is to use a custom structure to store the numbers instead of a built-in type. You could for instance store numbers like this:
template <int... Digits>
struct number<Digits... > { };
Note: For the sake of simplicity when adding, I store the digits in reverse order, so the number 275 is stored as number<5, 7, 2>.
Fibonacci only requires addition, so you simply have to define addition, e.g., a template add (see the end of the answer for the actual implementation).
You can then define the fib template quite easily:
template <int N>
struct fib_impl {
using type = add_t<
typename fib_impl<N-1>::type,
typename fib_impl<N-2>::type,
typename fib_impl<N-3>::type>;
};
template <>
struct fib_impl<0> { using type = number<0>; };
template <>
struct fib_impl<1> { using type = number<0>; };
template <>
struct fib_impl<2> { using type = number<1>; };
template <int N>
using fib = typename fib_impl<N>::type;
And with an appropriate output operator (see below), you can print the 100th Tribonacci number:
int main() {
std::cout << fib<100>{} << "\n";
}
Which outputs:
53324762928098149064722658
While the 100th is not present in the OEIS, you can check that the 37th one is correct:
static_assert(std::is_same_v<fib<37>, number<2, 5, 8, 6, 3, 4, 2, 3, 1, 1>>);
Implementation of operator<<:
std::ostream& operator<<(std::ostream &out, number<>) {
return out;
}
template <int Digit, int... Digits>
std::ostream& operator<<(std::ostream &out, number<Digit, Digits... >) {
// Do not forget that number<> is in reverse order:
return out << number<Digits... >{} << Digit;
}
Implementation of the add template:
This is a small cat utility to concatenate numbers:
// Small concatenation utility:
template <class N1, class N2>
struct cat;
template <int... N1, int... N2>
struct cat<number<N1... >, number<N2... >> {
using type = number<N1... , N2...>;
};
template <class N1, class N2>
using cat_t = typename cat<N1, N2>::type;
The actual implementation of the addition:
template <class AccNumber, int Carry, class Number1, class Number2>
struct add_impl;
template <class AccNumber, int Carry>
struct add_impl<AccNumber, Carry, number<>, number<>> {
using type = std::conditional_t<Carry == 0, AccNumber, cat_t<AccNumber, number<1>>>;
};
template <class AccNumber, int Carry,
int Digit2, int... Digits2>
struct add_impl<AccNumber, Carry, number<>, number<Digit2, Digits2...>> {
using type = typename add_impl<
cat_t<AccNumber, number<(Digit2 + Carry) % 10>>,
(Digit2 + Carry) / 10,
number<Digits2... >, number<>>::type;
};
template <class AccNumber, int Carry,
int Digit1, int... Digits1>
struct add_impl<AccNumber, Carry, number<Digit1, Digits1... >, number<>> {
using type = typename add_impl<
cat_t<AccNumber, number<(Digit1 + Carry) % 10>>,
(Digit1 + Carry) / 10,
number<Digits1... >, number<>>::type;
};
template <class AccNumber, int Carry,
int Digit1, int... Digits1, int Digit2, int... Digits2>
struct add_impl<AccNumber, Carry, number<Digit1, Digits1... >, number<Digit2, Digits2...>> {
using type = typename add_impl<
cat_t<AccNumber, number<(Digit1 + Digit2 + Carry) % 10>>,
(Digit1 + Digit2 + Carry) / 10,
number<Digits1... >, number<Digits2... >>::type;
};
A short wrapper:
template <class... Numbers>
struct add;
template <class Number>
struct add<Number> {
using type = Number;
};
template <class Number, class... Numbers>
struct add<Number, Numbers... > {
using type = typename add_impl<
number<>, 0, Number, typename add<Numbers... >::type>::type;
};
template <class... Numbers>
using add_t = typename add<Numbers... >::type;
I am not aware of ready-to-use arbirtrary precicion facitlities for templates. However, a toy number-type that can hold numbers bigger than long long is easy to write:
template <long long H,long long L>
struct my_number {
static const long long high = H;
static const long long low = L;
static const long long mod = 10000000000;
static void print() {
std::cout << high << setw(10) << setfill('0') << low;
}
};
It stores the last 10 digits of the result in low and the leading digits in high. Two my_numbers can be summed via
template <typename A,typename B>
struct sum {
static const long long low = (A::low + B::low) % A::mod;
static const long long high = A::high + B::high + (A::low + B::low) / A::mod;
using number = my_number<high,low>;
};
and for 3 numbers:
template <typename A,typename B,typename C>
struct sum3 { using number = typename sum<A,sum<B,C>>::number; };
As already mentioned, this is just a toy example. Anyhow, once you have a number type that can represent big enough numbers you just have to adjust you fib with minor modifications:
template<long long num> struct fib {
using result_t = typename sum3< typename fib<num-1>::result_t,
typename fib<num-2>::result_t,
typename fib<num-3>::result_t
>::number;
};
template<> struct fib<0> { using result_t = my_number<0,1>; };
template<> struct fib<1> { using result_t = my_number<0,1>; };
template<> struct fib<2> { using result_t = my_number<0,2>; };
template<> struct fib<3> { using result_t = my_number<0,4>; };
int main() {
fib<100>::result_t::print();
}
I couldn't find a reliable source for the correct value of fib<100>, so unfortunately I couldn't test against that.
Full example is here.
You can accomplish this using Boost version 1.72 and boost::multiprecision:
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
template <int x>
struct fib
{
static constexpr boost::multiprecision::uint1024_t value = x * fib<x - 1>::value;
};
template <>
struct fib<0>
{
static constexpr boost::multiprecision::uint1024_t value = 1;
};
int main()
{
std::cout << fib<100>::value;
}
Output:
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
This was run using Visual Studio 2019 and boost 1.72. Note that earlier versions of boost::multiprecision were not full constexpr, so this probably will not compile with earlier versions of boost.
EDIT:
Here is the third-class version. This is almost verbatim to the original poster's version, with the only difference being the usage of the constexpr-enabled big number class from boost:
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
template<long long num>
struct fib
{
static constexpr boost::multiprecision::uint1024_t value = fib<num - 1>::value + fib<num - 2>::value + fib<num - 3>::value;
};
template<>
struct fib<0>
{
static constexpr boost::multiprecision::uint1024_t value = 1;
};
template<>
struct fib<1>
{
static constexpr boost::multiprecision::uint1024_t value = 1;
};
template<>
struct fib<2>
{
static constexpr boost::multiprecision::uint1024_t value = 2;
};
template<>
struct fib<3>
{
static constexpr boost::multiprecision::uint1024_t value = 4;
};
int main()
{
std::cout << fib<100>::value;
}
Output:
180396380815100901214157639

C++ templates - How can I unpack a tuple of tuples of template arguments?

So I have this implementation of a tuple:
template<typename... TT>
struct Tuple {
enum{ size = sizeof...(TT) };
};
Now I'm trying to define a struct which gets a tuple of tuples to represent a 2D array in compile time. For example, usage:
template <int T>
struct Int {
enum { value = T };
};
typedef Matrix< Tuple<
Tuple < Int<1>, Int<2>, Int<3> >,
Tuple < Int<4>, Int<5>, Int<6> >
> > arr;
int width = arr::width; // width should be 3 as number of columns.
int length = arr::length; // length should be 2 as number of rows.
I have tried this approach:
template <typename TupleOfTuples>
struct Matrix;
template<typename ... TT>
struct Matrix<Tuple<Tuple<TT...>>> {
enum { width = Tuple<TT...>::size };
enum { length = Tuple<Tuple<TT...>>::size };
};
This seems to work ONLY when length = 1 (matrix of only one row).For every other length I get the error message:
error: incomplete type 'arr {aka Matrix<Tuple<Tuple<Int<1>, Int<2>, Int<3> >, Tuple<Int<4>, Int<5>, Int<6> > > >}' used in nested name specifier
int width = arr::width;
I have also tried to mess around with the struct's declaration but nothing seemed to work!How can I make this work?
What you did here can't work:
template<typename ... TT>
struct Matrix<Tuple<Tuple<TT...>>>
Because you create a specialization for Matrix with a Tuple that contains exactly one Tuple. Therefore template deduction fails for this case.
You need to extract the first tuple from the nested tuple and take it's size. This assumes that all nested tuples have the same size:
template <class T1, class... T>
struct first
{
using type = T1;
};
template <int T>
struct Int
{
static constexpr auto value = T;
};
template<typename... TT>
struct Tuple
{
static constexpr auto size = sizeof...(TT);
};
template<typename... TT>
struct Matrix;
template<typename... TT>
struct Matrix<Tuple<TT...>>
{
static constexpr auto width = Tuple<TT...>::size;
static constexpr auto length = first<TT...>::type::size;
};
int main()
{
using arr = Matrix< Tuple<
Tuple < Int<1>, Int<2>, Int<3> >,
Tuple < Int<4>, Int<5>, Int<6> >>>;
std::cout << arr::width << arr::length << std::endl;
}
This outputs 23

Nested Template Classes

I want to be able to create a generic nested template such that I can find the total size of all classes. To start, imagine for classes A, B, C, etc... each of which have a mSize member, and GetSize() function. I do the following process:
int main()
{
using Abc = A<B<C<>>>; // Imagine it is defined similarly to this for now.
Abc abc;
std::cout << abc.GetSize() << std::endl;
// For abc.GetSize(), this will do the following:
// 1. Go into A::GetSize().
// 2. This will return A::mSize + B::GetSize()
// 3. This will go into B::GetSize()
// 4. This will return B::mSize + C::GetSize()
// 5. Etc
// Overall, we will have the total size of A+B+C as
// A::mSize + B::mSize + C::mSize.
return 0;
}
It will recursively go through each template class until the end and call GetSize(). My current attempts to do so have been using template-templates and variadic templates.
template <template<typename> class First, template<typename> class ...Args>
class A
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{1};
};
template <template<typename> class First, template<typename> class ...Args>
class B
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{2};
};
template <template<typename> class First, template<typename> class ...Args>
class C
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{3};
};
This obviously has not worked. I would really like to be able to achieve the process described in int main().
Notes:
These classes don't necessarily have to be included, or be in order. We could have A<C> or B<E<C<F<>>>>. Ideally, it can be infinitely long.
I don't want to use polymorphism, wanting it to be resolved at runtime. I could have them all inherit from the same class, create a std::vector<Parent*>, push_back each child class, and iterate through using GetSize(). It would be nice to be able to define unique types such as A<B<>>, A<B<C<>>>, etc.
Since your mSize is the same for all instance, your method should be static, and since it looks like it is a constant, it should be a constexpr.
Here is an implementation that uses a general template and then partially instantiate it with specific sizes:
template <int Size, typename T>
struct Holder {
static constexpr int GetSize() {
return Size + T::GetSize();
}
};
template <int Size>
struct Holder<Size, void> {
static constexpr int GetSize() {
return Size;
}
};
template <typename T = void>
using A = Holder<1, T>;
template <typename T = void>
using B = Holder<2, T>;
template <typename T = void>
using C = Holder<3, T>;
Then you can test:
using AB = A<B<>>;
using ABC = A<B<C<>>>;
static_assert(AB::GetSize() == 1 + 2, "Oops!");
static_assert(ABC::GetSize() == 1 + 2 + 3, "Oops!");
Of course you can make A, B, C, ... extends Holder instead of partially instantiate it if you need it.
You could do something like:
#include <iostream>
#include <type_traits>
using namespace std;
template <class T>
struct A {
static constexpr int size = 1;
using inner_type = T;
};
template <class T>
struct B {
static constexpr int size = 2;
using inner_type = T;
};
//template <class T>
struct C {
static constexpr int size = 3;
using inner_type = void;
};
template <class T, class = void>
struct TotalSizeGetter {
static constexpr int get() {
return T::size + TotalSizeGetter<typename T::inner_type>::get();
}
};
template <class T>
struct TotalSizeGetter<T, typename enable_if<is_void<typename T::inner_type>::value>::type> {
static constexpr int get() {
return T::size;
}
};
int main() {
cout << TotalSizeGetter<A<B<C>>>::get() << endl;
}
This uses c++11 constexpr and enable_if but I see this is not a limitation as you use term variadic templates in your question...

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?

Initialise static const int with static function

I have a template class with some integers as arguments. One static const integer (call it Length) of this class needs to be calculated based on the arguments. The calculation does need a loop (as far as I know) so a simple expression won't help.
static int setLength()
{
int length = 1;
while (length <= someTemplateArgument)
{
length = length << 1;
}
return length;
}
The returned length should be used to init Length. Lengthis used as a fixed length of an array so I need it to be constant.
Is there a solution for this issue? I know that constexp could help but I can't use C11 or later.
Using metaprogramming. Implementation of C++11 enable_if taken from cppreference.com
#include <iostream>
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
template <int length, int arg, typename = void>
struct length_impl
{
static const int value = length_impl<(length << 1), arg>::value;
};
template <int length, int arg>
struct length_impl<length, arg, typename enable_if<(length > arg)>::type>
{
static const int value = length ;
};
template <int arg>
struct length_holder
{
static const int value = length_impl<1, arg>::value;
};
template<int n>
struct constexpr_checker
{
static const int value = n;
};
int main()
{
std::cout << constexpr_checker< length_holder<20>::value >::value;
}