Let's say I have a function
template<typename retScalar, typename... scalars>
retScalar func_scalar(scalars... items);
declared somewhere.
I now want a "array" version of this function
template<typename retScalar, typename... scalars>
std::array<retScalar, LEN> func_vec(std::tuple<std::array<scalars, LEN>...> vecs) {
std::array<retScalar, LEN> res; // initialized somehow
for (int i = 0; i < LEN; ++i) {
res[i] = func_scalar(/* ?? */);
}
return res;
}
I searched a lot and don't see any correct way to do that.
Thanks to another anwser, I found this solution, which I find pretty cool and probably useful for other people
#include <cstdio>
#include <tuple>
template<typename T>
struct myvect {
T data[4];
};
template<typename... Ts>
struct helper {
template<std::size_t... I>
static auto inner(int index, std::tuple<myvect<Ts>...> vects, std::index_sequence<I...>)
{
return std::make_tuple(std::get<I>(vects).data[index]...);
}
};
template<typename... Ts>
auto elements(int index, std::tuple<myvect<Ts>...> vectors)
{
return helper<Ts...>::template inner(index, vectors, std::index_sequence_for<Ts...>{});
}
template<typename retS, typename... args>
struct vectorize {
template<retS(*funcptr)(args...)>
static myvect<retS> func_vect(std::tuple<myvect<args>...> v) {
myvect<retS> res;
for (int i = 0; i < 4; ++i) {
res.data[i] = std::apply(funcptr, elements(i, v));
}
return res;
}
};
int test(int a, int b) {
return a + b;
}
int main() {
myvect<int> a { 1, 2, 3, 4 };
myvect<int> b { 2, 4, 6, 8 };
auto added = vectorize<int, int, int>::func_vect<&test>(std::make_tuple(a, b));
for (int i = 0; i < 4; ++i) {
printf("%d\n", added.data[i]);
}
}
Related
My code creates arrays, I need to implement deletions for it, but I don’t know how to do it beautifully and correctly.
main code
template<class T1>
auto auto_vector(T1&& _Size) {
return new int64_t[_Size]{};
}
template <class T1, class... T2>
auto auto_vector(T1&& _Size, T2&&... _Last)
{
auto result = new decltype(auto_vector(_Last...))[_Size];
for (int64_t i = 0; i < _Size; ++i) {
result[i] = auto_vector(_Last...);
}
return result;
}
this is the code that I want to combine with the first
template <class T1, class T2, class T3, class T4>
void del_vector(T4& _Del, T1& _Size, T2& _Size2, T3& _Size3) {
for (ptrdiff_t i = 0; i < _Size3; ++i) {
for (ptrdiff_t k = 0; k < _Size2; ++k) {
delete _Del[i][k];
}
delete _Del[i];
}
delete _Del;
}
int main()
{
auto map1 = auto_vector(_Size, _Size2, _Size3);
auto map2 = auto_vector(3, 4, 5, 7);
del_vector(map1, _Size, _Size2, _Size3);
return 0;
}
I do not like this option I would like something like that.
int main()
{
auto_vector map1(_Size, _Size2, _Size3);
del_vector map1(_Size, _Size2, _Size3);
//or so
auto_vector<_Size, _Size2, _Size3> map1;
del_vector<_Size, _Size2, _Size3> map1;
return 0;
}
the reason why I do this is because I cannot implement the same thing using just a vector
and I don’t understand why the vector does not work with dynamic arrays, the fact is that I do not know the exact data
_Size, _Size2, _Size3 = ? before compilation.
therefore I use new and all this I do only for his sake.
if it is useful to you to look at the data for tests
cout << " ---------TEST---------- " << endl;
for (ptrdiff_t i = 0; i < _Size3; ++i) {
for (ptrdiff_t k = 0; k < _Size2; ++k) {
for (ptrdiff_t j = 0; j < _Size; ++j) {
cout << map1[i][k][j] << " ";
}
cout << endl;
}
cout << endl;
}
cout << " ---------TEST---------- " << endl;
You have too many new operations in the code. Also del_vector doesn't make any sense in your preferred version as any decent class will deallocate its data in the destructor (lest it has no ownership over it).
What you need is to make a class or a template class that wraps things up.
#include <iostream>
#include <vector>
#include <array>
#include <type_traits>
using namespace std;
template<size_t index, size_t dim>
void ModifyArray(std::array<size_t,dim>& lcAarray){}
template<size_t index, size_t dim, typename... Args>
void ModifyArray(std::array<size_t, dim>& lcAarray, size_t arg, Args... args)
{
lcAarray[index] = arg;
ModifyArray<index+1>(lcAarray, args...);
}
template<typename... Args>
std::array<size_t, sizeof...(Args)> MakeArray(Args... args)
{
std::array<size_t, sizeof...(Args)> lclArray;
ModifyArray<0>(lclArray, args...);
return lclArray;
}
template< std::size_t dim >
class myMultiArray;
template<std::size_t dim, std::size_t crDim>
class MyMultiArrayIterator
{
public:
MyMultiArrayIterator(myMultiArray<dim>* multiArray, size_t index):
m_pMultiArray(multiArray),
m_index(index)
{}
template<size_t newDim = crDim+1, typename std::enable_if<newDim < dim, int>::type = 0>
MyMultiArrayIterator<dim, newDim> operator [] (size_t idx)
{
return MyMultiArrayIterator<dim, newDim>(m_pMultiArray, m_index + idx*m_pMultiArray->GetStep(crDim));
}
template<size_t newDim = crDim+1, typename std::enable_if<newDim == dim, int>::type = 0>
int& operator [] (size_t idx)
{
return m_pMultiArray->GetValue(m_index+idx*m_pMultiArray->GetStep(crDim));
}
private:
size_t m_index;
myMultiArray<dim>* m_pMultiArray;
};
template< std::size_t dim >
class myMultiArray
{
public:
myMultiArray() = default;
template<class... Args, typename std::enable_if<sizeof...(Args) == dim-1, int>::type = 0>
myMultiArray(size_t size0, Args... args)
{
m_sizes = MakeArray(size0, args...);
std::size_t uTotalSize = 1;
for (std::size_t i = 0; i < dim; i++)
{
m_steps[i] = uTotalSize;
uTotalSize *= m_sizes[i];
}
std::cout << uTotalSize << "\n";
m_data.resize(uTotalSize);
}
// resizes m_data to multiplication of sizes
int operator () (std::array < std::size_t, dim > indexes) const
{
return m_data[computeIndex(indexes)];
}
int &operator () (std::array < std::size_t, dim > indexes)
{
return m_data[computeIndex(indexes)];
}
// modify operator
// you'll probably need more utility functions for such a multi dimensional array
int GetValue(size_t index) const
{
return m_data[index];
}
int &GetValue(size_t index)
{
return m_data[index];
}
size_t GetSize(size_t index) const
{
return m_sizes[index];
}
size_t GetStep(size_t index) const
{
return m_steps[index];
}
MyMultiArrayIterator<dim, 1> operator [] (size_t index)
{
return MyMultiArrayIterator<dim, 1>(this, index*m_steps[0]);
}
private:
size_t computeIndex(std::array < std::size_t, dim > indexes)
{
size_t location = 0;
for(size_t i=0; i< dim; i++)
{
location += m_steps[i]*indexes[i];
}
return location;
}
private:
std::vector < int > m_data;
std::array < std::size_t, dim > m_sizes;
std::array < std::size_t, dim > m_steps;
};
template<typename... Args>
myMultiArray<sizeof...(Args)> MakeMyMultiArray(Args... args)
{
return myMultiArray<sizeof...(Args)>(args...);
}
int main ()
{
auto mapMA = MakeMyMultiArray(3,4,5);
mapMA({2ull,3ull,4ull}) = 7;
std::cout << mapMA({{2ull,3ull,4ull}}) << "\n";
std::cout << mapMA[2][3][4];
return 0;
}
I have a class with an int template parameter. Under some circumstances I want it to output an error message. This message should be a concatenated string from some fixed text and the template parameters. For performance reasons I'd like to avoid building up this string at runtime each time the error occurs and theoretically both, the string literal and the template parameter are known at compiletime. So I'm looking for a possibility to declare it as a constexpr.
Code example:
template<int size>
class MyClass
{
void onError()
{
// obviously won't work but expressing the concatenation like
// it would be done with a std::string for clarification
constexpr char errMsg[] = "Error in MyClass of size " + std::to_string (size) + ": Detailed error description\n";
outputErrorMessage (errMsg);
}
}
Using static const would allow to compute it only once (but at runtime):
template<int size>
class MyClass
{
void onError()
{
static const std::string = "Error in MyClass of size "
+ std::to_string(size)
+ ": Detailed error description\n";
outputErrorMessage(errMsg);
}
};
If you really want to have that string at compile time, you might use std::array, something like:
template <std::size_t N>
constexpr std::size_t count_digit() {
if (N == 0) {
return 1;
}
std::size_t res = 0;
for (int i = N; i; i /= 10) {
++res;
}
return res;
}
template <std::size_t N>
constexpr auto to_char_array()
{
constexpr auto digit_count = count_digit<N>();
std::array<char, digit_count> res{};
auto n = N;
for (std::size_t i = 0; i != digit_count; ++i) {
res[digit_count - 1 - i] = static_cast<char>('0' + n % 10);
n /= 10;
}
return res;
}
template <std::size_t N>
constexpr std::array<char, N - 1> to_array(const char (&a)[N])
{
std::array<char, N - 1> res{};
for (std::size_t i = 0; i != N - 1; ++i) {
res[i] = a[i];
}
return res;
}
template <std::size_t ...Ns>
constexpr std::array<char, (Ns + ...)> concat(const std::array<char, Ns>&... as)
{
std::array<char, (Ns + ...)> res{};
std::size_t i = 0;
auto l = [&](const auto& a) { for (auto c : a) {res[i++] = c;} };
(l(as), ...);
return res;
}
And finally:
template<int size>
class MyClass
{
public:
void onError()
{
constexpr auto errMsg = concat(to_array("Error in MyClass of size "),
to_char_array<size>(),
to_array(": Detailed error description\n"),
std::array<char, 1>{{0}});
std::cout << errMsg.data();
}
};
Demo
Here's my solution. Tested on godbolt:
#include <string_view>
#include <array>
#include <algorithm>
void outputErrorMessage(std::string_view s);
template<int N> struct cint
{
constexpr int value() const { return N; }
};
struct concat_op {};
template<std::size_t N>
struct fixed_string
{
constexpr static std::size_t length() { return N; }
constexpr static std::size_t capacity() { return N + 1; }
template<std::size_t L, std::size_t R>
constexpr fixed_string(concat_op, fixed_string<L> l, fixed_string<R> r)
: fixed_string()
{
static_assert(L + R == N);
overwrite(0, l.data(), L);
overwrite(L, r.data(), R);
}
constexpr fixed_string()
: buffer_ { 0 }
{
}
constexpr fixed_string(const char (&source)[N + 1])
: fixed_string()
{
do_copy(source, buffer_.data());
}
static constexpr void do_copy(const char (&source)[N + 1], char* dest)
{
for(std::size_t i = 0 ; i < capacity() ; ++i)
dest[i] = source[i];
}
constexpr const char* data() const
{
return buffer_.data();
}
constexpr const char* data()
{
return buffer_.data();
}
constexpr void overwrite(std::size_t where, const char* source, std::size_t len)
{
auto dest = buffer_.data() + where;
while(len--)
*dest++ = *source++;
}
operator std::string_view() const
{
return { buffer_.data(), N };
}
std::array<char, capacity()> buffer_;
};
template<std::size_t N> fixed_string(const char (&)[N]) -> fixed_string<N - 1>;
template<std::size_t L, std::size_t R>
constexpr auto operator+(fixed_string<L> l, fixed_string<R> r) -> fixed_string<L + R>
{
auto result = fixed_string<L + R>(concat_op(), l , r);
return result;
};
template<int N>
constexpr auto to_string()
{
auto log10 = []
{
if constexpr (N < 10)
return 1;
else if constexpr(N < 100)
return 2;
else if constexpr(N < 1000)
return 3;
else
return 4;
// etc
};
constexpr auto len = log10();
auto result = fixed_string<len>();
auto pow10 = [](int n, int x)
{
if (x == 0)
return 1;
else while(x--)
n *= 10;
return n;
};
auto to_char = [](int n)
{
return '0' + char(n);
};
int n = N;
for (int i = 0 ; i < len ; ++i)
{
auto pow = pow10(10, i);
auto digit = to_char(n % 10);
if (n == 0 && i != 0) digit = ' ';
result.buffer_[len - i - 1] = digit;
n /= 10;
}
return result;
}
template<int size>
struct MyClass
{
void onError()
{
// obviously won't work but expressing the concatenation like
// it would be done with a std::string for clarification
static const auto errMsg = fixed_string("Error in MyClass of size ") + to_string<size>() + fixed_string(": Detailed error description\n");
outputErrorMessage (errMsg);
}
};
int main()
{
auto x = MyClass<10>();
x.onError();
}
Results in the following code:
main:
sub rsp, 8
mov edi, 56
mov esi, OFFSET FLAT:MyClass<10>::onError()::errMsg
call outputErrorMessage(std::basic_string_view<char, std::char_traits<char> >)
xor eax, eax
add rsp, 8
ret
https://godbolt.org/z/LTgn4F
Update:
The call to pow10 is not necessary. It's dead code which can be removed.
Unfortunately your options are limited. C++ doesn't permit string literals to be used for template arguments and, even if it did, literal concatenation happens in the preprocessor, before templates come into it. You would need some ghastly character-by-character array definition and some manual int-to-char conversion. Horrible enough that I can't bring myself to make an attempt, and horrible enough that to be honest I'd recommend not bothering. I'd generate it at runtime, albeit only once (you can make errMsg a function-static std::string at least).
I'm looking for a small function that is able to transform a std::array by adding increasing values. The function must be a compile time function.
I was able to write a small constexpr function which does so for an array of length 3, but I was unable to generalize it to std::arrays of arbitrary lengths. I also failed to generalize it to contain something different than chars.
Does anyone knows how to do it?
#include <array>
#include <iostream>
#include <valarray>
constexpr std::array<char,3> obfuscate(const std::array<char,3>& x) {
return std::array<char, 3>{x.at(0)+1, x.at(1) + 2, x.at(2) + 3 };
}
/* Won't compile
template<typename T,typename S, template<typename, typename> L=std::array<T, U>>
constexpr L<T,U> obfuscate(const L<T, U>& x) {
return {x.at(0) + 1, x.at(0) + 2, x.at(0) + 3 };
}
*/
std::ostream& operator<<(std::ostream& str, const std::array<char, 3>& x) {
for (auto i = 0; i < 3; i++) {
str << x.at(i);
}
return str;
}
int main(int argc, char** args) {
std::array<char, 3> x{ 'a','b','c' };
std::cout << x << std::endl;
std::cout << obfuscate(x) << std::endl;
// std::cout << obfuscate<3>(x) << std::endl;
}
You can use std::index_sequence:
template<class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> helper (const std::array<T, N> &x, std::index_sequence<Is...>) {
return std::array<T, N>{static_cast<T>(x.at(Is)+Is+1)...};
}
template<class T, std::size_t N>
constexpr std::array<T, N> obfuscate(const std::array<T, N> &x) {
return helper(x, std::make_index_sequence<N>{});
}
There are a few methods that use tuple packs, these are great except that MSVC has a performance problem compiling large strings.
I've found this compromise works well in MSVC.
template<typename I>
struct encrypted_string;
template<size_t... I>
struct encrypted_string<std::index_sequence<I...>>
{
std::array<char, sizeof...(I)+1> buf;
constexpr static char encrypt(char c) { return c ^ 0x41; }
constexpr static char decrypt(char c) { return encrypt(c); }
constexpr explicit __forceinline encrypted_string(const char* str)
: buf{ encrypt(str[I])... } { }
inline const char* decrypt()
{
for (size_t i = 0; i < sizeof...(I); ++i)
{
buf[i] = decrypt(buf[i]);
}
buf[sizeof...(I)] = 0;
return buf.data();
}
};
#define enc(str) encrypted_string<std::make_index_sequence<sizeof(str)>>(str)
And somewhere later
auto stringo = enc(R"(
kernel void prg_PassThru_src(const global unsigned short * restrict A, int srcstepA, int srcoffsetA,
global float * restrict Beta, int srcstepBeta, int srcoffsetBeta,
int rows, int cols) {
int x = get_global_id(0);
int y0 = get_global_id(1);
if (x < cols) {
int srcA_index = mad24(y0, srcstepA / 2, x + srcoffsetA / 2);
int srcBeta_index = mad24(y0, srcstepBeta / 4, x + srcoffsetBeta / 4);
Beta[srcBeta_index] = A[srcA_index];
}
}
//somewhere later
cv::ocl::ProgramSource programSource(stringo.decrypt());
You can see this guy's talk for more sophisticated methods:
https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation.pdf
I have an integer N which I know at compile time. I also have an std::array holding integers describing the shape of an N-dimensional array. I want to generate nested loops, as described bellow, at compile time, using metaprogramming techniques.
constexpr int N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
auto f = [/* accept object which uses coords */] (auto... coords) {
// do sth with coords
};
// This is what I want to generate.
for(int i = 0; i < shape[0]; i++) {
for(int j = 0; j < shape[1]; j++) {
for(int k = 0; k < shape[2]; k++) {
for(int l = 0; l < shape[3]; l++) {
f(i,j,k,l) // object is modified via the lambda function.
}
}
}
}
Note the parameter N is known at compile time but might change unpredictably between compilations, hence I can't hard code the loops as above. Ideally the loop generation mechanism will provide an interface which accepts the lambda function, generates the loops and calls the function producing the equivalent code as above. I am aware that one can write an equivalent loop at runtime with a single while loop and an array of indices, and there are answers to this question already. I am, however, not interested in this solution. I am also not interested in solutions involving preprocessor magic.
Something like this (NOTE: I take the "shape" as a variadic template argument set..)
#include <iostream>
template <int I, int ...N>
struct Looper{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
Looper<N...>()(f, x..., i);
}
}
};
template <int I>
struct Looper<I>{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
f(x..., i);
}
}
};
int main()
{
int v = 0;
auto f = [&](int i, int j, int k, int l) {
v += i + j + k + l;
};
Looper<1, 3, 5, 2>()(f);
auto g = [&](int i) {
v += i;
};
Looper<5>()(g);
std::cout << v << std::endl;
}
Assuming you don't want total loop unrolling, just generation of i, j, k etc. argument tuples for f:
#include <stdio.h>
#include <utility> // std::integer_sequence
template< int dim >
constexpr auto item_size_at()
-> int
{ return ::shape[dim + 1]*item_size_at<dim + 1>(); }
template<> constexpr auto item_size_at<::N-1>() -> int { return 1; }
template< size_t... dim >
void call_f( int i, std::index_sequence<dim...> )
{
f( (i/item_size_at<dim>() % ::shape[dim])... );
}
auto main()
-> int
{
int const n_items = ::shape[0]*item_size_at<0>();
for( int i = 0; i < n_items; ++i )
{
call_f( i, std::make_index_sequence<::N>() );
}
}
I suppose this is exactly what you asked for:
#include <array>
#include <iostream>
constexpr int N{4};
constexpr std::array<int, N> shape {{1,3,5,2}};
// Diagnositcs
template<typename V, typename ...Vals>
struct TPrintf {
constexpr static void call(V v, Vals ...vals) {
std::cout << v << " ";
TPrintf<Vals...>::call(vals...);
}
};
template<typename V>
struct TPrintf<V> {
constexpr static void call(V v) {
std::cout << v << std::endl;
}
};
template<typename ...Vals>
constexpr void t_printf(Vals ...vals) {
TPrintf<Vals...>::call(vals...);
}
// Unroll
template<int CtIdx, typename F>
struct NestedLoops {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[CtIdx]; ++i) {
NestedLoops<CtIdx + 1, F>::call(f, idx..., i);
}
}
};
template<typename F>
struct NestedLoops<N-1, F> {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[N-1]; ++i) {
f(idx..., i);
}
}
};
template<typename F>
void nested_loops(const F& f) {
NestedLoops<0, F>::call(f);
}
int main()
{
auto lf = [](int i, int j, int k, int l) {
t_printf(i,j,k,l);
};
nested_loops(lf);
return 0;
}
Another variant of the same thing:
template <size_t shape_index, size_t shape_size>
struct Looper
{
template <typename Functor>
void operator()(const std::array<int, shape_size>& shape, Functor functor)
{
for (int index = 0; index < shape[shape_index]; ++index)
{
Looper<shape_index + 1, shape_size>()
(
shape,
[index, &functor](auto... tail){ functor(index, tail...); }
);
}
}
};
template <size_t shape_size>
struct Looper<shape_size, shape_size>
{
template <typename Functor>
void operator()(const std::array<int, shape_size>&, Functor functor)
{
functor();
}
};
template <size_t shape_size, typename Functor>
void loop(const std::array<int, shape_size>& shape, Functor functor)
{
Looper<0, shape_size>()(shape, functor);
}
Example of use:
constexpr size_t N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
void f(int i, int j, int k, int l)
{
std::cout
<< std::setw(5) << i
<< std::setw(5) << j
<< std::setw(5) << k
<< std::setw(5) << l
<< std::endl;
}
// ...
loop(shape, f);
Live demo
I am having an issue with different types in a implementation of the quick sort algorithm using iterator templates and I cannot figure out what's going on.
The algorithm is the following:
template <typename I> void ordenacion_rapida(I i, I j, int n0=1)
{
int n = j-i;
if (n<=n0)
ordenacion_insercion<I>(i, j);
else
{
I p = pivote(i, j);
ordenacion_rapida<I>(i, p);
ordenacion_rapida<I>(p+1, j);
}
}
template <typename I> I pivote(I i, I j)
{
I p = i;
typedef typename iterator_traits<I>::value_type tipo;
tipo x = *(i);
for (I k=i+1; k<j; ++k)
if (*(k)<=x)
{
++p;
tipo aux = *(p);
*(p) = *(k);
*(k) = aux;
}
*(i) = *(p);
*(p) = x;
}
template <typename I> void ordenacion_insercion(I i, I j)
{
typedef typename iterator_traits<I>::value_type tipo;
for (I k=i+1; k<j; ++k)
{
tipo x = *(k);
while (k!=i && x<*(k-1))
{
*(k) = *(k-1);
--k;
}
*(k) = x;
}
}
Forgive me if there is an exccessive quantity of code but the problem might be in any line, which I have exhaustively analyzed.
The thing is that when I try to sort a vector<double or vector<float> I am reported an error whereas there is no such problem when I use vector<int>.
Where is the problem?
I am unable to see anything wrong with your code, it works perfectly fine. The only issue is you forgot to return something inside pivote.
#include <iterator>
#include <vector>
using namespace std;
template <typename I> void ordenacion_insercion(I i, I j)
{
// snip
}
template <typename I> I pivote(I i, I j)
{
// snip
// Assuming you intended to return P
return p;
}
template <typename I> void ordenacion_rapida(I i, I j, int n0=1)
{
// snip
}
#include <iostream>
int main() {
std::vector<double> v = { 1.2f, 0.5f, 3.5f, 0.2f };
ordenacion_rapida(v.begin(), v.end());
for (unsigned int i = 0; i < v.size(); i++)
std::cout << v[i] << " ";
} // 0.2 0.5 1.2 3.5