I am looking for a way to optionally include members of a c++ class to generate POD structs. I found that this works fairly well, but is nonstandard:
#include <iostream>
template <int v, int n, int t>
struct Point
{
int vertex[v];
float normal[n];
double texcoord[t];
};
int main()
{
std::cout << (sizeof (Point<0,0,1>)) << std::endl;
std::cout << (sizeof (Point<1,0,1>)) << std::endl;
std::cout << (sizeof (Point<1,1,2>)) << std::endl;
std::cout << (sizeof (Point<0,0,0>)) << std::endl;
return 0;
}
So Point<1,0,0> would only contain a vertex (the int type will actually be a vector3 type in practice), and so on. The main reason for this is to easily support interleaved arrays for OpenGL.
Maybe try something like this:
#include <type_traits>
template <unsigned int v, unsigned int n, unsigned int t>
struct Point
{
int data[v + n + t];
template <unsigned int i>
typename std::enable_if<(i < v), int &>::type
vertex() { return data[i]; }
template <unsigned int i>
typename std::enable_if<(i < v + n), int &>::type
normal() { return data[v + i]; }
template <unsigned int i>
typename std::enable_if<(i < v + n + t), int &>::type
texcoord() { return data[v + n + i]; }
};
Usage:
Point<1,1,2> p;
p.vertex<0>() = 50;
std::array<T, 0> is valid, unlike T[0] and really is a better solution all around. Unfortunately, and since this is only available for C++11, I can't figure out if its Boost namesake boost::array also has such support.
It is also possible to write an array-like helper yourself.
You can do this, but you would need specializations.
Edit: Matched with new question requirement of different type per array. Made template arguments unsigned though.
template <> struct Point<0, 0, 0> {};
template <unsigned v> struct Point<v, 0, 0> { int vertex[v]; };
template <unsigned n> struct Point<0, n, 0> { float normal[n]; };
template <unsigned t> struct Point<0, 0, t> { double texcoord[t]; };
template <unsigned v, unsigned n> struct Point<v, n, 0> {
int vertex[v];
float normal[n];
};
template <unsigned v, unsigned t> struct Point<v, 0, t> {
int vertex[v];
double texcoord[t];
};
template <unsigned n, unsigned t> struct Point<0, n, t> {
float normal[n];
double texcoord[t];
};
Each specialization leaves out the associated array when its corresponding template parameter has value 0. For three items as shown, the enumeration of specializations is not overly large, and provides exactly the same syntax for accessing the elements as your original post but using standard C++ constructs.
Extending this technique beyond 3 arrays would be cumbersome. However, it could be managed with a script to generate the specializations for you.
Related
consider the following example of a compile-time "vector".
#include <iostream>
template <int n, int...ns>
struct static_vector {
static constexpr int value = n;
static_vector<ns...> rest;
};
template <int n>
struct static_vector<n> {
static constexpr int value = n;
void* rest;
};
template <int n, class sv>
constexpr int access_nth() {
static_assert(n >= 0, "vector size out of bound");
if constexpr(n == 0) {
return sv::value;
} else {
static_assert(!std::is_same_v<decltype(sv::rest), void *>, "vector size out of bound");
return access_nth<n-1, decltype(sv::rest)>();
}
}
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
constexpr int nth = access_nth<5, decltype(a)>();
std::cout << nth << std::endl;
}
I am mostly satisfied with what we can do now: define a vector and then get the nth element out of it. The one thing I found that not satisfying is this: I have to use void * as a dummy in the base case (where the vector only holds one element and no tail...)
I tried to have a specialisation like this:
template <>
struct static_vector<> {
}
to represent the empty vector. But it seems that the compiler always rejects this definition with the following error:
<source>:16:8: error: too few template arguments for class template 'static_vector'
struct static_vector<> {
^
What should I do here so I can have an empty vector?
Thanks a lot.
But why recursion ?
You tagged C++17 so you can use template folding, so... what about as follows ?
#include <iostream>
template <int ... Is>
struct static_vector
{
template <std::size_t N>
int get () const
{
static_assert( N < sizeof...(Is), "index out of bound" );
std::size_t i{};
int ret;
( ... , (N == i++ ? ret = Is : 0) );
return ret;
}
};
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
std::cout << a.get<3u>() << std::endl;
}
Specializations must conform to the base template declaration. Since at least one int is required by the base template, this does not compile.
You can make this work by declaring the template to take any number of int arguments, then specializing every case that takes one or more arguments. The base declaration is then the empty case:
template <int...>
struct static_vector {
// Instantiated only for the no-argument case
};
template <int n>
struct static_vector<n> {
// One-argument specialization
};
template <int n, int... ns>
struct static_vector<n, ns...> {
// Two-or-more-argument specialization
};
I was wondering if it was possible to have nested C++ template and still be able to access the template values ?
To explain, here is what I currently have:
template <int first, int... tail>
struct ConstIntVector:ConstIntVector<tail...>
{};
template <int first>
struct ConstIntVector<first>
{};
template<int f1, int... t1>
int prod(const ConstIntVector<f1, t1...>, const int* a) {
return f1 * (*a) + prod(ConstIntVector<t1...>(), a+1);
}
This way, I can access the f1 value in my prod function. But I would like to do it like this:
template<ConstIntVector<int f1, int... t1>>
int prod(const int* a) {
return f1 * (*a) + prod<ConstIntVector<t1...>>(a+1);
}
It is possible ?
Partial template specializations aren't allowed for member functions. But you can use a helper struct:
namespace detail
{
template <typename T>
struct prodHelper;
template <int f1, int... t1>
struct prodHelper<ConstIntVector<f1, t1...> >
{
static int eval(const int* a) {
return f1 * (*a) + prodHelper<ConstIntVector<t1...>>::eval(a+1);
}
};
}
template <typename T>
int prod(const int* a) {
return detail::prodHelper<T>::eval(a);
}
Another option would be to utilize ConstIntVector structs to carry useful information:
template <int First, int... Tail>
struct ConstIntVector {
constexpr static int value = First;
using tail = ConstIntVector<Tail...>;
};
template <int First>
struct ConstIntVector<First> {
constexpr static int value = First;
using got_no_tail = void;
};
template <class CIV, typename CIV::tail* = nullptr>
int prod(const int* a) {
return CIV::value * (*a) + prod<typename CIV::tail>(a+1);
}
template <class CIV, typename CIV::got_no_tail* = nullptr>
int prod(const int* a) {
return CIV::value * (*a);
}
Just be aware, that recursion is neither necessary nor desirable to solve these kinds of TMP problems. First, it is better to simply define your vector like this:
template <int... Is>
struct ConstIntVector{};
That way you can have zero length vectors as well, which is convenient in handling edge cases (witness the fact that std::array can be length 0).
Next, lets write our product function. We'll modify it in two ways: first we'll infer the integer by trivially passing our ConstIntVector by value, and second we'll use pack expansions to avoid recursion.
template<int... Is>
int prod(const int* a, ConstIntVector<Is...>) {
int index = 0;
int sum = 0;
int [] temp = {(sum += (a[index++] * Is))...};
return sum;
}
Usage:
std::vector<int> v{1,2,3};
using v2 = ConstIntVector<4,5,6>;
std::cerr << prod(v.data(), v2{});
Live example: http://coliru.stacked-crooked.com/a/968e2f9594c6b292
Link to example of highly optimized assembly: https://godbolt.org/g/oR6rKe.
How about
template<int I>
int prod(const int* a) {
return I * (*a);
}
template<int I, int I2, int... Is>
int prod(const int* a) {
return I * (*a) + prod<I2, Is...>(a + 1);
}
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?
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;
}
I'm trying to use templates to unroll a loop in C++ as follows.
#include <iostream>
template< class T, T i >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T >
struct printDown< T, 0 > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
When I compile w/ g++ 3.4.4 in Cygwin, I get the following error.
tmp.cpp:12: error: type T' of
template argument0' depends on
template parameter(s)
What am I doing wrong? Do I need to somehow annotate the 0 to say that it's of type T?
Thanks in advance.
Have you tried int i instead of T i?
Why this happens? From 14.5.5/8,
— The type of a template parameter
corresponding to a specialized
non-type argument shall not be
dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
Therefore when you apply partial specialization, the type of 0 is T (dependent on a parameter of the specialization). There are two choices, one is to make it none dependent, e.g., change T i to int i, and second is to apply explicit specialization rather than partial specialization.
Both solutions have been given out by others, so I'm not gonna to repost them here. At least you know the reason. It's defined by standard.
As pointed out by phooji your implementation suffers from a small issue: it quickly generates a long list of calls, which will make compilers choke quickly.
You could work around this by implementing a slightly more complicated version, using binary decomposition. I'll make it generic on a functor too, cause I am lazy.
// Signature
template <Functor F, unsigned N>
struct UnrolledLoop;
We need a helper template, which keeps an offset of the parameter to pass
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl;
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 0, OffSet>
{
static F run(F f) { return f; }
};
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 1, OffSet>
{
static F run(F f) { f(OffSet); return f; }
};
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl
{
static F run(F f) {
F f2 = UnrolledImpl<F, N/2, OffSet>::run(f);
return UnrolledImpl<F, N - N/2, OffSet + N/2>::run(f2);
}
};
And you can implement UnrolledLoop simply:
template <Functor F, unsigned N>
struct UnrolledLoop
{
static F run(F f) { return UnrolledImpl<F, N, 0>::run(f); }
}
Note that you could provide specialization for more values of N (3, 4 for example) to be nicer on the compiler.
What about adding this to your example:
template struct printDown< int, 0 >{
static void run(void) {
std::cout << 0 << "\n";
} };
The compiler cannot cast 0 to int automatically without knowing T's type in advance.
Just found this out. Apparently one can do something like this.
template< class T, T i, bool b = (i == 0) >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, true > {
static void run(void) {
std::cout << 0 << "\n";
}
};
I had no idea that could be done. Very Prologish & very nice.
You can make the parameter a type parameter to work this around
template< bool > struct bool_ { };
template< class T, T i, typename = bool_<true> >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, bool_<i == 0> > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
This way you can specify any conditions you want in the partial specializations.