Partial class template specialization c++11 - c++

I am trying to compile the below code, but I am getting the error:
wrong number of template arguments
template<int start, int end, int step>
struct range{};
template<int start, int end>
struct range<start, end, 1>{};
template<int end>
struct range<0, end, 1>{};
int main() {
auto r1 = range<0, 5, 2>{};
auto r2 = range<5, 15>{}; //error: wrong number of template arguments
auto r3 = range<10>{}; //error: wrong number of template arguments
}
How can I create partial template class object?

If you want the ability to specify start before end, but also to have a default argument for start you could do something like this:
template <int... Args>
struct range {
static_assert(sizeof...(Args) > 0 && sizeof...(Args) <= 3,
"Must pass 1-3 args");
using ArgPack = std::tuple<std::integral_constant<int, Args>...>;
template <int Size, typename Then, typename Else>
using select_value = typename std::conditional_t<
(sizeof...(Args) > Size), Then, Else
>::type;
static constexpr int start = select_value<1,
std::tuple_element<0, ArgPack>, std::integral_constant<int,0>
>::value;
static constexpr int end = select_value<1,
std::tuple_element<1, ArgPack>, std::tuple_element<0, ArgPack>
>::value;
static constexpr int step = select_value<2,
std::tuple_element<2, ArgPack>, std::integral_constant<int,1>
>::value;
};
This has exactly the usage which you desire, like this:
int main()
{
using a = range<1,1,2>;
static_assert(a::start == 1 && a::end == 1 && a::step == 2, "wat");
using b = range<1,1>;
static_assert(b::start == 1 && b::end == 1 && b::step == 1, "wat");
using c = range<3>;
static_assert(c::start == 0 && c::end == 3 && c::step == 1, "wat");
}
Live Demo

You need to specify all the template arguments according to the primary template's declaration, then which one selected will be determined according to the template arguments.
auto r1 = range<0, 5, 2>{}; // the primary template
auto r2 = range<5, 15, 1>{}; // the 1st partial specified template
auto r3 = range<0, 10, 1>{}; // the 2nd partial specified template
If you want to specify fewer template arguments you might want default template arguments:
template<int end, int start = 0, int step = 1>
struct range{};
auto r1 = range<5, 0, 2>{}; // end->5, start->0, step->2
auto r2 = range<15, 5>{}; // end->15, start->5, step->1
auto r3 = range<10>{}; // end->10, start->0, step->1
Note that I changed the order of the template parameters, because if the default argument is specified for a template parameter, each subsequent template parameter must have a default argument too.

Related

How to generalize this function with variadic templates c++

I have the following function. It converts two bindings of T0 and T1 to a binding of a tuple<T0,T1>
The function is as follows
template<typename T0, typename T1>
typename RxBinding<std::tuple<T0,T1>>::Ptr
Combine(RxBinding<T0>::Ptr b0, RxBinding<T1>::Ptr b1)
{
using Tuple = std::tuple<T0,T1>;
RxBinding<Tuple>::Ptr binding = makeValueBinding(std::make_tuple(b0->Get(),b1->Get()));
// Break the reference cycle.
auto bindingWeak = std::weak_ptr<RxBinding<Tuple>>(binding);
auto s0 = b0->Subscribe([bindingWeak,b1](T0 const & v0){
auto b = bindingWeak.lock();
if(b)
b->Update(std::make_tuple(v0,b1->Get()));
});
auto s1 = b1->Subscribe([bindingWeak,b0](T1 const & v1){
auto b = bindingWeak.lock();
if(b)
b->Update(std::make_tuple(b0->Get(),v1));
});
auto sN = binding->Subscribe([b0,b1](std::tuple<T0,T1> const & t){
b0->Update(std::get<0>(t));
b1->Update(std::get<1>(t));
});
binding->CleanupWith << s0 << s1 << sN;
return binding;
}
Don't worry too much about what a binding is. Assume they work. I'm looking for a pattern to generalise this using C++11 variadic templates so I can have N bindings as input rather than just two and convert them to a single binding?
template <typename ...T>
typename RxBinding<std::tuple<T...>>::Ptr
Combine( RxBinding<T>::Ptr args...) /* is this possible ?? */
{
using Tuple = std::tuple<T...>;
auto binding = makeValueBinding(std::make_tuple( /* what do do here with args ?? */ ));
// Break the reference cycle.
RxBinding<Tuple>::Ptr bindingWeak = std::weak_ptr<RxBinding<Tuple>>(binding);
// Make N subscriptions b0,b1,....bN with the weak reference above
/* What to do here ?? */
// Make the final subscription
auto sN = binding->Subscribe([](std::tuple<T...> const & t){
// Update the N bindings.
/* what to do here ? */
});
// Add all subscriptions to the cleanup on the final binding
/* not sure what to do here */
return binding;
}
From RxBinding<T>::Ptr T can't be deduced, as it's a non-deduced context because of nested types (see example 1) under Non-deduced contexts on cppreference and godbolt example), so the original example shouldn't have worked with argument deduction. With that in mind having typename RxBinding<Ts>::Ptr ...args will work the same way as it did before (note the syntax having ... before the argument name). I changed the variadic type template to Ts instead of T, to better represent that it's variadic.
With auto binding = makeValueBinding(std::make_tuple( /* what do do here with args ?? */ )); you can use a pack expansion with the pattern args->Get(), so the final line will be
auto binding = makeValueBinding(std::make_tuple(args->Get()...));.
Creation of the variables s0, s1, and so on is not trivial, so I'll get back to it at the end.
To make the final subscribtion, you will need to use a helper function to expand the tuple:
template<typename ...ArgTypes, typename ...Ts, std::size_t ...Ns>
void FinalSubscribeHelper(
std::tuple<ArgTypes...> const &args,
std::tuple<Ts...> const &t,
std::index_sequence<Ns...>
)
{
// using C++17's fold expressions (https://en.cppreference.com/w/cpp/language/fold)
((std::get<Ns>(args)->Update(std::get<Ns>(t))), ...); // we use the comma operator for expansion
return;
// using array initializers for C++11
using ArrayT = int[sizeof...(ArgTypes)];
ArrayT{
((
std::get<Ns>(args)->Update(std::get<Ns>(t)) // this is the pattern
), 0)...
};
return;
}
So the final subscribtion is
auto sN = binding->Subscribe([=](std::tuple<Ts...> const &t){
// Update the N bindings.
FinalSubscribeHelper(std::make_tuple(args...), t, std::make_index_sequence<sizeof...(Ts)>{});
});
For adding all subscriptions to the cleanup you will need another helper function:
template<typename BindingT, typename ...STs, typename SNT, std::size_t ...Ns>
void CleanupHelper(
BindingT const &binding,
std::tuple<Ts...> const &s,
SNT const &sN
std::index_sequence<Ns...>
)
{
// using C++17's fold expressions (https://en.cppreference.com/w/cpp/language/fold)
(binding->CleanupWith << ... << std::get<Ns>(s)) << sN;
return;
// using array initializers for C++11
/*
this only works if
binding->CleanupWith << s0 << s1 << sN;
is equivalent to
binding->CleanupWith << s0;
binding->CleanupWith << s1;
binding->CleanupWith << sN;
*/
using ArrayT = int[sizeof...(ArgTypes)];
ArrayT{
((
binding->CleanupWith << std::get<Ns>(s)
), 0)...
};
binding->CleanupWith << sN;
return;
}
So the final cleanup is
CleanupHelper(binding, s, sN, std::make_index_sequence<sizeof...(Ts)>{});.
Now get back to creating s. To create the callback I assume you want Update to be called as
b->Update(std::make_tuple(/* bM->Get() with M = 0, 1, 2, ..., I-1 */, vI, /* bM->Get() with M = I+1, I+2, ..., N-1 */));. For this you need two index sequences, one from 0 to I-1 and one from I+1 to N-1. For that let's create some type aliases to make the needed std::index_sequence's.
template<std::size_t Offset, typename T>
struct AddOffset;
template<std::size_t Offset, std::size_t ...Ns>
struct AddOffset<Offset, std::index_sequence<Ns...>>
{
using type = std::index_sequence<(Ns + Offset)...>;
};
template<std::size_t Offset, typename T>
using AddOffsetT = typename AddOffset<Offset, T>::type;
// this creates a std::index_sequence with the values
// Start, Start+1, Start+2, ..., End-1
template<std::size_t Start, std::size_t End>
using MakeIndexSequenceInRange = AddOffsetT<Start, std::make_index_sequence<End - Start>>;
To create s you will need a few helper functions:
template<typename BindingT, typename ...ArgTypes, typename VT, std::size_t ...Ns, std::size_t ...Ms>
void SubscribeCallbackHelper(
BindingT const &b,
std::tuple<ArgTypes...> const &args,
VT const &v,
std::index_sequence<Ns...>,
std::index_sequence<Ms...>
)
{
b->Update(std::make_tuple(std::get<Ns>(args)->Get()..., v, std::get<Ms>(args)->Get()...));
}
template<typename BindingWeakT, typename ...ArgTypes, std::size_t ...Ns>
auto CreateS(
BindingWeakT const &bindingWeak,
std::tuple<ArgTypes...> const &args,
std::index_sequence<Ns...>
) -> decltype(std::make_tuple(std::get<Ns>(args)->Subscribe(std::declval<void(*)(ArgTypes const &)>())...))
// I'm not sure this decltype will work, if you have C++14 you should be able to just use auto as a return type
{
return std::make_tuple(
std::get<Ns>(args)->Subscribe([bindingWeak, args](ArgTypes const &v) {
auto b = bindingWeak.lock();
if (b)
SubscribeCallbackHelper(b, args, v, MakeIndexSequenceInRange<0, Ns>{}, MakeIndexSequenceInRange<Ns+1, sizeof...(ArgTypes)>{});
})
);
}
So the creation of s will be
auto s = CreateS(bindingWeak, std::make_tuple(args...), std::make_index_sequence<sizeof...(Ts)>{});

How to take a class, that uses a parameter pack and typename, as an input parameter for a function(c++)

I created a class that takes a typename template variable and a parameter pack. In the next step i want to be able to pass two objects of that class to my function.
My main problem is, passing the template parameters and the objects correctly to be able to use my function.
My class implementation.
//auto as template parameter is for non-type parameter(c++17)
template <auto value> constexpr auto DIM = value;
//constexpr on values in header files(c++17)
inline constexpr auto const DIM3 = DIM <3>;
inline constexpr auto const DIM2 = DIM <2>;
enum Index : int {lower = 0, upper = 1};
template<int base, int exponent>
int constexpr pow(){
if constexpr(exponent == 0){
return 1;
}else{
return base * pow<base, exponent-1>();
}
}
template<int Size, typename T>
struct Array{
T array[Size];
Array(const T * a){
for(int i = 0; i < Size; i++){
array[i] = a[i];
}
}
};
//auto as template parameter is for non-type parameters(c++17)
template<typename T = double, auto ...IndicesN>
class MatrixND{
private:
const Array<pow<DIM3, sizeof...(IndicesN)>(), T> matrix;
public:
MatrixND(const T * arr): matrix(arr){}
template<auto ...args>
auto constexpr getElement(){
}
};
The function that takes MatrixND objects:
template<auto posT1, auto posT2, typename A, typename B>
auto constexpr function(const MatrixND<A> tensor1, const MatrixND<B> tensor2){
return 0;
}
I tried the following, but it throws an error message "no matching function call":
const double arrayc[27] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27};
auto matrix1 = new MatrixND<double, upper, lower, lower>(arrayc);
function<1,1, decltype(matrix1), decltype(matrix1)>(matrix1, matrix1);
The error message:
error: no matching function for call to ‘function<1, 1, MatrixND<double, (Index)1, (Index)0, (Index)0>*, MatrixND<double, (Index)1, (Index)0, (Index)0>*>(MatrixND<double, (Index)1, (Index)0, (Index)0>*&, MatrixND<double, (Index)1, (Index)0, (Index)0>*&)’
contraction<1,1, decltype(matrix1), decltype(matrix1)>(matrix1, matrix1);
You need to add the parameter packs to the template parameters of function. Using
template<auto posT1, auto posT2, typename A, typename B, auto ...AIndicesN, auto ...BIndicesN>
auto constexpr function(const MatrixND<A, AIndicesN...> tensor1, const MatrixND<B, BIndicesN...> tensor2){
return 0;
}
Allows you to call function like
auto foo = function<1,1>(matrix1, matrix1);
Do note that for this to compile with your code you need to change
auto matrix1 = new MatrixND<double, upper, lower, lower>(arrayc);
to
auto matrix1 = MatrixND<double, upper, lower, lower>(arrayc);
since you don't actually want a pointer to a MatrixND but an actual MatrixND object.
When you call the function as
function<1,1, decltype(matrix1), decltype(matrix1)>(matrix1, matrix1);
you say that the template arguments A and B are decltype(matrix1), meaning they are really MatrixND<double, upper, lower, lower>.
That in turn means that e.g. the argument tensor1 will have the type const MatrixND<MatrixND<double, upper, lower, lower>>. Which is not what you pass.
A possible solution would be to not use MatrixND<A> (and MatrixND<B>) in the argument list, but only
template<auto posT1, auto posT2, typename A, typename B>
auto constexpr function(const A tensor1, const B tensor2){
return 0;
}
And you should probably pass references instead of values as arguments as well.
If you do like above with the function you also don't need the template arguments for the types of A and B as that would be deduced by the compiler:
function<1,1>(matrix1, matrix1);

Why do I have to specialize recursive template variables?

So I wrote an answer here: https://stackoverflow.com/a/56569397/2642059 which strives to compute log2 at compile time like so:
template <unsigned int x>
constexpr enable_if_t<x != 0U, int> log2 = 1 + log2<x / 2U>;
template <>
constexpr int log2<1U> = 0;
This works fine but I didn't feel like I should have had to specialize:
template <unsigned int x>
constexpr enable_if_t<x != 0U, int> log2 = x < 4U ? 1 : 1 + log2<x / 2U>;
But this gives me the error:
In substitution of template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = (0u != 0u); _Tp = int]:
prog.cpp:7:61: recursively required from constexpr std::enable_if_t<true, int> log2<4u>
prog.cpp:7:61: required from constexpr std::enable_if_t<true, int> log2<8u>
prog.cpp:10:11: required from here
/usr/include/c++/6/type_traits:2523:61: error: no type named type in struct std::enable_if<false, int>
Is there a way I can prevent the compiler from unrolling the recursion too far?
You use recursion to calculate log2. Each and every recursive operation in our life needs the leaf case.
In case of recursive leaf functions, the leaf case can be provided with non-recursive returns. However, with template variables the only way to provide the leaf case would be with specialization, there is no other way at all.
I believe, that you can achieve the very same goals with constexpr function and no TMP:
#include <type_traits>
constexpr int log2(int arg) {
if (arg == 0) return 0;
if (arg == 1) return 0;
return 1 + log2(arg / 2u);
}
constexpr std::integral_constant<int, log2(16)> z; // z.value == 4
This works with both run-time and compile-time arguments and generally should be preferred over pure TMP solution, except for educational purposes.
For educational or other undisclosed purposes, you can use exclusive compile-time like that:
#include <type_traits>
template<int arg>
constexpr int log2(std::integral_constant<int, arg> ) {
static_assert(arg > 0, "Bad arg to log2!");
if constexpr (arg == 1) {
return 0;
} else {
return 1 + log2(std::integral_constant<int, arg / 2> {});
}
}
int k = log2(std::integral_constant<int, 16>{});

static_assert each parameter's size in parameter pack

I am trying to check whether each parameter within a parameter pack can be stored within 8 bytes (sizeof <= 8)
I have the function signature:
template <typename Return, typename... Arguments>
inline auto invoke(std::uint64_t hash, Arguments... arguments) -> Return
Using fold expressions, I have tried:
static_assert((sizeof(arguments) <= 8 && ...));
Which failed to compile with unexpected token '...', expected 'expression' - I assume it's invalid or incorrect?
Using C++20 concepts and constraints, I assume something along the lines of is possible?
template <typename Return, typename... Arguments> requires (sizeof(arguments) <= 8 || ...)
inline auto invoke(std::uint64_t hash, Arguments... arguments) -> Return
I assume there is a way of using the standard library to say check that a type fits within a std::uint64_t say also?
With C++20 concepts, there are many ways how to achieve the desired behavior. For instance:
template <typename T, size_t N>
concept bool SizeLessEqual = sizeof(T) <= N;
template <SizeLessEqual<8>... Types>
void f() { }
int main() {
f<bool, char, int, double>();
f<std::string>(); // error
}
Live demo: https://wandbox.org/permlink/Q9tifNVplsx9BjGN
Another option is your solution:
template <typename... Types> requires ((sizeof(Types) <= 8) && ...)
void f() { }
Or, e.g.:
template <typename... Types> requires (std::max({ sizeof(Types)... }) <= 8)
void f() { }
Try this way:
#include <cstdint>
#include <utility>
template <typename... Arguments>
auto invoke(std::uint64_t hash, Arguments... arguments)
{
auto check = []( auto&& argument )
{
static_assert( sizeof(argument) <= 8, "size too large" );
return 0;
};
auto dummy = { 0, ( check(std::forward<Arguments>(arguments)), 0) ... };
return 0;
}
int main()
{
invoke( 0UL, '1' );
invoke( 0UL, '1', 2 );
invoke( 0UL, '1', 2, 3UL );
//invoke( 0UL, '1', 2, 3UL, static_cast<long double>(1.0) );
return 0;
}
Using the comma operator and the initializer_list to do the trick.
With C++17, we can further trim the code to:
template <typename... Arguments>
auto invoke(std::uint64_t hash, Arguments... arguments)
{
auto check = []( auto&& argument )
{
static_assert( sizeof(argument) <= 8, "size too large" );
};
(check(std::forward<Arguments>(arguments)), ...);
}
taking the advantage of fold expressions.
I do not understand the downvotes, but as this is my last post in stackoverflow, I uploaded a live example at wandbox: https://wandbox.org/permlink/NZbqpRaTs2TFOCwG

How to get the i-th element from an std::tuple when i isn't know at compile-time?

I have a variable i of type std::size_t and a tuple of type std::tuple. I want to get the i-th element of the tuple. I tried this:
// bindings... is of type const T&...
auto bindings_tuple = std::make_tuple(bindings...);
auto binding = std::tuple_element<i, const T&...>(bindings_tuple);
But I get this compile error saying that the first template argument must be an integral constant expression:
error: non-type template argument of type 'std::size_t' (aka 'unsigned long') is not an integral constant expression
Is it possible to get the i-th element of a tuple, and how to do that?
I would like to do this without using boost, if possible.
This is possible:
struct Functor
{
template<typename T>
void operator()(T& t) const { std::cout << t << std::endl; }
};
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_index(int, std::tuple<Tp...> &, FuncT)
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_index(int index, std::tuple<Tp...>& t, FuncT f)
{
if (index == 0) f(std::get<I>(t));
for_index<I + 1, FuncT, Tp...>(index-1, t, f);
}
auto t = make_tuple(1, 2, "abc", "def", 4.0f);
int i = 2; // for example
for_index(i, t, Functor());
This code will print:
abc
Working sample on ideone: sample
You cannot. That's not what a tuple is for. If you need dynamic access to an element, use std::array<T,N>, which is almost identical to std::tuple<T,...,T> but gives you the dynamic [i]-operator; or even a fully dynamic container like std::vector<T>.
This is probably not what OP wants, but anyway, it is possible to return the i-th element using a run-time i provided you return a variant type such as boost::variant or boost::any,
#include <tuple>
#include <stdexcept>
#include <boost/variant.hpp>
template <size_t n, typename... T>
boost::variant<T...> dynamic_get_impl(size_t i, const std::tuple<T...>& tpl)
{
if (i == n)
return std::get<n>(tpl);
else if (n == sizeof...(T) - 1)
throw std::out_of_range("Tuple element out of range.");
else
return dynamic_get_impl<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
}
template <typename... T>
boost::variant<T...> dynamic_get(size_t i, const std::tuple<T...>& tpl)
{
return dynamic_get_impl<0>(i, tpl);
}
For example:
#include <string>
#include <iostream>
int main()
{
std::tuple<int, float, std::string, int> tpl {4, 6.6, "hello", 7};
for (size_t i = 0; i < 5; ++ i)
std::cout << i << " = " << dynamic_get(i, tpl) << std::endl;
return 0;
}
will print:
0 = 4
1 = 6.6
2 = hello
3 = 7
terminate called after throwing an instance of 'std::out_of_range'
what(): Tuple element out of range.
Aborted
(The boost::variant<T...> requires g++ 4.7)
The question here, what would be the type return type if that would be possible? It has to be known at compile time, but tuple may contain elements of different types.
Let's assume we have a tuple of three elements:
auto tuple = std::make_tuple(10, "", A());
using tuple_type = decltype(tuple);
Apparently, getting N-th element doesn't make much sense. What type would it be? It's not known until runtime. However, rather than getting N-th element you can apply a function to it, given that all elements support some common protocol:
void process(int n)
{
if (n == 0)
func(std::get<0>(tuple));
else if (n == 1)
func(std::get<1>(tuple));
else if (n == 2)
func(std::get<2>(tuple));
}
This code "dynamically" processes element, given the index n. The common protocol in this example is function func which can do something meaningful with all possible types used in the tuple.
However, writing such code by hand is tedious, we want to make it more generic. Let's start with extracting the application function, so we can reuse same process function for different functors:
template<template<typename > class F>
void process(int n)
{
if (n == 0)
{
using E = typename std::tuple_element<0, tuple_type>::type;
F<E>::apply(std::get<0>(tuple));
}
else if (n == 1)
{
using E = typename std::tuple_element<1, tuple_type>::type;
F<E>::apply(std::get<1>(tuple));
}
else if (n == 2)
{
using E = typename std::tuple_element<2, tuple_type>::type;
F<E>::apply(std::get<2>(tuple));
}
}
In this case F could be implemented as something like:
// Prints any printable type to the stdout
struct printer
{
static void apply(E e)
{
std::cout << e << std::endl;
}
}
Let's make compiler to generate all of that code, let's make it generic:
constexpr static std::size_t arity = std::tuple_size<tuple_type>::value;
template<int N>
struct wrapper
{
template<template<typename, typename ... > class F>
static void apply_to(tuple_type& tuple, int idx)
{
if (idx)
// Double recursion: compile and runtime.
// Compile-time "recursion" will be terminated once
// we reach condition N == tuple arity
// Runtime recursion terminates once idx is zero.
wrapper<N + 1>::template apply_to<F>(tuple, idx - 1);
else
{
// idx == 0 (which means original index is equal to N).
using E = typename std::tuple_element<N, tuple_type>::type;
F<E>::apply(std::get<N>(tuple));
}
}
};
// Termination condition: N == arity.
template<>
struct wrapper<arity>
{
template<template<typename, typename ... > class F>
static void apply_to(tuple_type&, int)
{
// Throw exception or something. Index is too big.
}
};
Usage:
wrapper<0>::template apply_to<printer>(tuple, 2);
Making it completely generic is another story, though. At least it needs to be independent of the tuple type. Then, you probably want to generify return type of the functor, so you can return meaningful result. Third, making functor to accept extra parameters.
P.S. I am not real C++ developer, so the approach above could be total nonsence. However, I found it useful for my microcontroller project where I want as much as possible to be resolved at compile time and yet be generic enough, so I can shuffle things around easily. For example, a "menu" in my project is basically a tuple of "actions", there each action is a separate class which supports simple protocol like "print your label at current position on LCD" and "activate and run your UI loop".