Suppose there are several template classes (structures), objects of which form the sequence - let's call them N_mod(N - specifier for particular class), and special class, that defines the first element in the sequence - First_mod. Each class, except First_mod, has its own "interface builder" - N_builder - template class:
template<int targ>
struct First_mod //First element in sequence - without appropriate builder interface
{ };
//Let's consider two types of N_mod - A_mod and B_mod
template<int targ, int param>
struct A_mod
{ };
template<int param>
struct A_builder//Builder for A_mod objects
{ };
template<int targ, int param>
struct B_mod
{ };
template<int param>
struct B_builder//Builder for B_mod objects
{ };
Now I need to generate sequence of First_mod and N_mod objects from existing sequense of appropriate N_builders in accordance with simple rule:
if N_Mod(i) equals A_mod then targ(i) = param(i) - targ(i-1),
else(i.e. N_Mod(i) equals B_mod) targ(i) = param(i) * targ(i-1)
My sketches for clarity:
template<typename...builders>
struct mod_seq_gen
{
typedef /*generated First_mod, A_mod and B_mod sequence pack. How to do it?*/ modseq;
};
template<typename...builders>
struct Container
{
std::tuple</*here must be mod-sequence generator that creates
mod parameters pack and unpacks them:*/
mod_seq_gen<builders...>::modseq
> mod_sequence;
};
int main()
{
/*In this case must be generated next sequence and stored in
* mod_sequence tuple:
* First_mod<3> - A_mod<5-3, 5> - B_mod<2*(5-3), 2>
*/
Container<First_mod<3>, A_builder<5>, B_builder<2>> obj;
}
I'm asking to help in the implementation of mod_seq_gen, or some other tips for the whole task.
First I'll dump the (compiling) solution:
#include <tuple>
#include <utility>
#include <iostream>
template<int targ>
struct First_mod //First element in sequence - without appropriate builder interface
{ void print() { std::cout << "First_mod["<<targ<<"]" << std::endl; } };
//Let's consider two types of N_mod - A_mod and B_mod
template<int targ, int param>
struct A_mod
{ void print() { std::cout << "A_mod["<<targ<<", "<<param<<"]" << std::endl; } };
template<int param>
struct A_builder//Builder for A_mod objects
{
// publish the template parameter (not necessary)
static const int param_value = param;
// provide a way to compute the current targ
static constexpr int calc_targ(int prev_targ)
{
return param - prev_targ;
}
// provide a way to build the type
template < int targ >
using type = A_mod<targ, param>;
};
template<int targ, int param>
struct B_mod
{ void print() { std::cout << "B_mod["<<targ<<", "<<param<<"]" << std::endl; } };
template<int param>
struct B_builder//Builder for B_mod objects
{
static const int param_value = param;
static constexpr int calc_targ(int prev_targ)
{
return prev_targ * param;
}
template < int targ >
using type = B_mod<targ, param>;
};
// just a helper, wonder if there's something in the Standard Library o.O
template < typename... Tuples >
using tuple_cat_types = decltype(tuple_cat( std::declval<Tuples>()... ));
// the generator of the tuple
template < typename TFirst_mod, typename... TBuilders >
struct gen;
// restrict the first type to a specialization of `First_mod`
// isn't necessary, strictly speaking. We just need the first targ.
// Could as well require a nested `static const int targ = ..;`
template < int first_targ, typename... TBuilders >
struct gen < First_mod<first_targ>, TBuilders... >
{
// recursive helper for the types to be built
// general case for no template arguments in the pack
template < int prev_targ, typename... TBuilders2 >
struct helper { using type = std::tuple<>; };
// specialized case for recursion
// note: the recursion here occurs as a nested typedef, not inheritance
// (simplifies use of calculated targ)
template < int prev_targ, typename TBuilder, typename... TBuilders2 >
struct helper<prev_targ, TBuilder, TBuilders2...>
{
// build type using builder
static const int targ = TBuilder::calc_targ(prev_targ);
using built_type = typename TBuilder::template type<targ>;
// recurse
using further_types = typename helper<targ, TBuilders2...>::type;
// concatenate tuple
using type = tuple_cat_types<std::tuple<built_type>, further_types>;
};
// concatenate tuple with First_mod
using type = tuple_cat_types<std::tuple<First_mod<first_targ>>,
typename helper<first_targ, TBuilders...>::type>;
};
int main()
{
gen<First_mod<3>, A_builder<5>, B_builder<2>>::type x;
static_assert(std::tuple_size<decltype(x)>::value == 3, "!");
std::get<0>(x).print();
std::get<1>(x).print();
std::get<2>(x).print();
}
Slightly easier with a builder for First_mod:
template<int param>
struct First_builder
{
static constexpr int calc_targ(int /* discarded */)
{
return param;
}
template < int targ >
using type = First_mod<targ>;
};
/* ... */
// the generator of the tuple
template < int prev_targ, typename... TBuilders >
struct gen
{ using type = std::tuple<>; };
template < int prev_targ, typename TBuilder, typename... TBuilders2 >
struct gen<prev_targ, TBuilder, TBuilders2...>
{
// build type using builder
static const int targ = TBuilder::calc_targ(prev_targ);
using built_type = typename TBuilder::template type<targ>;
// recurse
using further_types = typename gen<targ, TBuilders2...>::type;
// concatenate tuple
using type = tuple_cat_types<std::tuple<built_type>, further_types>;
};
int main()
{
const int discarded = 0;
gen<discarded, First_builder<3>, A_builder<5>, B_builder<2>>::type x;
static_assert(std::tuple_size<decltype(x)>::value == 3, "!");
std::get<0>(x).print();
std::get<1>(x).print();
std::get<2>(x).print();
}
Related
Is there a way to allow two or more templates instanciations to mutually refer to each other ?
Example :
/* invalid C++ */
/* we suppose MyTemplate1 and MyTemplate2 are declared */
typedef MyTemplate1<MyInstance2> MyInstance1;
typedef MyTemplate2<MyInstance1> MyInstance2;
I suppose there is none, still asking just in case I missed something.
Adding more precision, I want to achieve such a construction :
/* invalid C++ */
#include <iostream>
template <typename typeT> struct MyStruct1 {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
typeT::print(i - 1);
}
}
};
template <typename typeT> struct MyStruct2 {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
typeT::print(i - 1);
}
}
};
/* of course this is invalid, since you can't reference MyInstance2
before it is declared */
typedef MyStruct1<MyInstance2> MyInstance1;
typedef MyStruct2<MyInstance1> MyInstance2;
int main() {
MyInstance1::print(5);
return 0;
}
output should be :
MyStruct1 : 5
MyStruct2 : 4
MyStruct1 : 3
MyStruct2 : 2
MyStruct1 : 1
MyStruct2 : 0
Please note I'm not trying to achieve a similar output, but a similar construct, where two (or more) templates instances refer to each other
with as few as possible additional code : it shall be easy to do mutual reference instantiation. However, for the implementation code of the two templates, I don't care if they are complicated.
Here's a solution that at least gives the correct output. If it's also a viable solution for your use case is not very clear though but maybe it can at least help you clarify your question a bit more.
#include <iostream>
template <template <typename> typename TemplateT> struct TemplateType {
template <typename typeT>
static void print(unsigned i) {
TemplateT<typeT>::print(i);
}
};
template <typename typeT> struct MyStruct1 {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
typeT::template print<TemplateType<MyStruct1>>(i - 1);
}
}
};
template <typename typeT> struct MyStruct2 {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
typeT::template print<TemplateType<MyStruct2>>(i - 1);
}
}
};
typedef MyStruct1<TemplateType<MyStruct2>> MyInstance1;
int main() {
MyInstance1::print(5);
return 0;
}
One way is to use class forward declaration:
template<typename T> class M
{
static int foo(int i) { return i ? T::foo(i - 1) : 0; }
};
struct A;
struct B;
struct A : M<B>{};
struct B : M<A>{};
Not same code exactly but you have recursion.
I finally found a satisfying construct, which involves using a tierce struct acting as a context to declare subs elements. It isn't forcibly the best solution for anyone, and I will probably have to adapt it a bit more to fit my very need, but here is the code :
#include <iostream>
#include <type_traits>
template <typename K, typename T> struct TypePair {
typedef K key;
typedef T type;
};
template <typename Context, typename P0, typename... PN> struct TypeMap {
template <typename K> struct get {
typedef typename std::conditional<
std::is_same<typename P0::key, K>::value,
typename P0::type::template actual<Context>,
typename TypeMap<Context, PN...>::template get<K>::type>::type type;
};
};
struct TypeNotFound {};
template <typename Context, typename P> struct TypeMap<Context, P> {
template <typename K> struct get {
typedef
typename std::conditional<std::is_same<typename P::key, K>::value,
typename P::type::template actual<Context>,
TypeNotFound>::type type;
};
};
/* defining a context to link all classes together */
template <typename... TN> struct Context {
template <typename K> struct Access {
typedef typename TypeMap<Context<TN...>, TN...>::template get<K>::type type;
};
};
/* templates we want to cross ref, note that context is passed as a parameter*/
template <typename ContextT, typename Id2> struct MyStruct1Actual {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
ContextT::template Access<Id2>::type::print(i - 1);
}
}
};
template <typename ContextT, typename Id1> struct MyStruct2Actual {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
ContextT::template Access<Id1>::type::print(i - 1);
}
}
};
/* wrappers to not have to always pass context when instancing templates */
template <typename type> struct MyStruct1 {
template <typename ContextT> using actual = MyStruct1Actual<ContextT, type>;
};
template <typename type> struct MyStruct2 {
template <typename ContextT> using actual = MyStruct2Actual<ContextT, type>;
};
/* Enum and dummy id, could simply use Enum actually, but using classes a Id
can prove to be more elegant with complex structures, expecially as it could be
used to automatically create pairs instead of having to precise Id */
enum Ids : int { Struct1, Struct2 };
template <Ids id> struct Id {};
// instancing all stuff withing context
// clang-format off
typedef Context<
TypePair< Id<Struct1>, MyStruct1< Id<Struct2> > >,
TypePair< Id<Struct2>, MyStruct2< Id<Struct1> > >
> Ctx;
// clang-format on
typedef Ctx::Access<Id<Struct1>>::type S1;
int main() {
S1::print(5);
return 0;
}
Shortening names an giving more meaning than Context or TypePair will be mandatory, but the idea is here.
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
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...
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;
}
Say I have a template declaration like this:
template <class A, class B, class C = A (&)(B)>
How would I make it so that I could have a variable amount of objects of type C? Doing class C ...c = x won't work because variadic template arguments can't have default values. So this is what I've tried:
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (&type)(B);
};
template <class F, class B, typename helper<F(B)>::type ... C>
void f(C ...c) { // error
}
But up to the last part I get error messages. I don't think I'm doing this right. What am I doing wrong here?
I think you can use the following approach. First, some machinery for type traits. This allows you to determine if the types in an argument pack are homogeneous (I guess you want all functions to have the same signature):
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
Then, some more type traits to figure out the signature of a generic function:
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
And finally, this is how you would define your variadic function template:
template <typename... F>
void foo(F&&... f)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
// ...
}
Here is a short test:
int fxn1(double) { }
int fxn2(double) { }
int fxn3(string) { }
int main()
{
foo(fxn1, fxn2); // OK
foo(fxn1, fxn2, fxn3); // ERROR! not homogeneous signatures
return 0;
}
Finally, if you need an inspiration on what to do once you have that argument pack, you can check out a small library I wrote (from which part of the machinery used in this answer is taken). An easy way to call all the functions in the argument pack F... f is the following (credits to #MarkGlisse):
initializer_list<int>{(f(forward<ArgType>(arg)), 0)...};
You can easily wrap that in a macro (just see Mark's answer to the link I posted).
Here is a complete, compilable program:
#include <iostream>
#include <type_traits>
using namespace std;
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
template <typename F>
void foo(F&& f)
{
cout << f(42) << endl;
}
template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
cout << f(42) << endl;
foo(fs...);
}
int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }
int main()
{
foo(fxn1, fxn2, fxn3); // OK
// foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures
return 0;
}
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (*type)(B);
};
template<class F, class B>
void f()
{
}
template <class F, class B, typename... C>
void f(typename helper<F(B)>::type x, C... c)
{
std::cout << x(B(10)) << '\n';
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int main()
{
f<int,int>(identity,half,square,cube);
}
Here's a modified version that can deduce types:
template<class F, class B>
void f(F(*x)(B))
{
x(B());
}
template <class F, class B, typename... C>
void f(F(*x)(B), C... c)
{
f(x);
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int string_to_int(std::string) { return 42; }
int main()
{
f(identity,half,square,cube);
// f(identity,half,string_to_int);
}