I want to simulate a chain of particles either in the up position or the down position. To this end I made a class that inherits from bitset. It looks like:
#include <bitset>
using namespace std;
template <size_t N>
class State : public bitset<N> {
public:
State<N>();
State<N>(size_t b);
long int E();
private:
size_t length;
};
template<unsigned long N>
State<N>::State()
: std::bitset<N>(), length(N)
{}
template<unsigned long N>
State<N>::State(size_t b)
: std::bitset<N>(b), length(N)
{}
Once such an object is instantiated using a certain length, I would like to find the energy associated to such an object. I want to do this
#include "state.h"
long int State::E(){
long int e = 0;
for (size_t i = 1; i != length; ++i)
e += (test[i] == test[i - 1]) ? 1 : -1;
return e;
}
I receive the error
state/state.cc:3:10: error: ‘template<long unsigned int N> class State’ used without template parameters
long int State::E(){
^~~~~
state/state.cc: In function ‘long int E()’:
state/state.cc:5:27: error: ‘length’ was not declared in this scope
for (size_t i = 1; i != length; ++i)
^~~~~~
state/state.cc:6:11: error: ‘test’ was not declared in this scope
e += (test[i] == test[i - 1]) ? 1 : -1;
^~~~
I understand this to mean that the compiler does not recognize that E() is a member function of my class due to a missing template argument. However, I was hoping there is a way that I can call s.E() on a State<20> object for instance. So once the object is instantiated I would like to be able to call E() without having to again specify the size. Is this possible? Thanks in advance!
There are two issues here: defining the member function E() of the class template State<N>, and accessing the test() member function of the dependent base class bitset<N>.
template<size_t N>
long int State<N>::E(){
long int e = 0;
for (size_t i = 1; i != length; ++i)
e += (this->test(i) == this->test(i - 1)) ? 1 : -1;
}
Note both the template<size_t N> and the State<N> as well as the this-> in front of test. See this Q&A for a detailed explanation.
Final note: also be careful: it's test() (parentheses) and operator[] (brackets) in std::bitset.
In the definition of member function of tempalte class, you must specify the template parameters as you did for the constructor.
The error "lenght not declared" should be fixed also by this change.
template <size_t N>
long int State<N>::E(){
long int e = 0;
for (size_t i = 1; i != length; ++i)
e += (test(i) == test(i - 1)) ? 1 : -1;
return e;
}
Related
I want to use a templated structure in order to mimic an array of doubles in 4 dimensions, the maximum size for each dimension is know in compilation time. Therefore, I think that using templates structure will give a chance to gain performance. You can find my attempt for the implementation bellow.
The code compiles unless that I attempt to instantiate one structure. I don't understand what is the problem with the code bellow, suggestions will be very appreciated.
Even more, I want to do two improvements if possible: 1) I want to be capable of use data of type float and of type double 2) Will be fancy to have some kind of overloaded operator that enables to assign values to the records of data in a similar way as T(N,L,M,J)=val in place of having to use T.assign(N,L, M,J,value). Again, suggestions will be very appreciated.
My aim is to fill the data in T_4D as fast as possible.
#include <iostream>
#include <cstring> // for memset
using namespace std;
template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10,double *data=NULL>
struct T_4D {
enum {SIZE = dim_N*dim_L*dim_M*dim_J };
enum {LEN1 = dim_N };
enum {LEN2 = dim_L };
enum {LEN3 = dim_M };
enum {LEN4 = dim_J };
static void create()
{
data=(double *)malloc(SIZE*sizeof(double));
memset(data, 0.0, SIZE*sizeof(*data));
}
static size_t multi_index(const size_t N) {
return N;
}
static size_t multi_index(const size_t N,const size_t L) {
return L*dim_N + N;
}
static size_t multi_index(const size_t N,const size_t L, const size_t M) {
return (M*dim_L + L)*dim_N + N;
}
static size_t multi_index(const size_t N,const size_t L, const size_t M,const size_t J) {
return ((J*dim_M + M)*dim_L + L)*dim_N + N;
}
double operator()(size_t N,size_t L, size_t M, size_t J){
return data[multi_index(N,L,M,J)];
}
static void assign(size_t N,size_t L, size_t M, size_t J,double value){
data[multi_index(N,L,M,J)]=value;
}
};
int main()
{
double *instance;
T_4D<3,3,3,10,instance> T;
T.create();
return 0;
}
The compilation errors are:
./main.cpp: In function ‘int main()’:
./main.cpp:49:17: error: the value of ‘instance’ is not usable in a constant expression
T_4D<3,3,3,10,instance> T;
^
./main.cpp:48:11: note: ‘instance’ was not declared ‘constexpr’
double *instance;
^
./main.cpp:49:25: error: ‘instance’ is not a valid template argument because ‘instance’ is a variable, not the address of a variable
T_4D<3,3,3,10,instance> T;
^
./main.cpp:50:5: error: request for member ‘create’ in ‘T’, which is of non-class type ‘int’
T.create();
^
Makefile:197: recipe for target 'obj/main.o' failed
make: *** [obj/main.o] Error 1
If all of your dimensions are known at compile time, there is no need for you to allocate dynamic memory. Simply use:
std::aligned_storage_t<sizeof( T ) * SIZE, alignof( T )> data;
You don't even need to initialize anything since you're working with POD types. If you want to zero the memory out, just use this:
for ( std::size_t i = 0; i < SIZE; ++i )
*( reinterpret_cast<T*>( &data ) + i ) = 0;
This will be the most efficient implementation, since we use static contiguous memory. You'll have to implement proper indexing, but that's not too difficult.
Actually, just use T data[ SIZE ]; or std::array<T, SIZE> data.
Also, remove the double* template parameter, these cannot be changed, so it can't be used for your data.
Using double* data = NULL as a template parameter does not seem right. You can use a double* as a template parameter but you can't assign to it as you are doing with:
data=(double *)malloc(SIZE*sizeof(double));
You can remove that as a template parameter and make it a member variable of the class.
template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10>
struct T_4D {
double* data;
...
and then allocate memory for it in the constructor instead of in the static member function.
T_4D() : data(new double[SIZE])
{
memset(data, 0.0, SIZE*sizeof(*data));
}
Remember to follow The Rule of Three and The Rule of Five since you are allocating memory from the heap.
Then, main can simply be:
int main()
{
T_4D<3,3,3,10> T;
return 0;
}
#include <iostream>
#include <string>
using namespace std;
template <class T> int IsSubArr(T& a, int a_len, T& b, int b_len)
{
int i,j;
bool found;
int k;
T& s=a,l=b;
int s_len = (a_len < b_len) ? a_len : b_len; // find the small array length
if (s_len == a_len) // check to set pointers to small and long array
{
s = a;
l = b;
}
else
{
s = b;
l = a;
}
for (i = 0; i <= a_len-s_len; i++) //loop on long array
{
found = true;
k=i;
for (j=0; j<s_len; j++) // loop on sub array
{
if (s[j] != l[i])
{
found = false;
break;
}
k++;
}
}
if (found)
return i;
else
return -1;
}
/******* main program to test templates ****/
int main()
{
int array[5] = {9,4,6,2,1};
int alen = 5;
int sub_arr[3] = {6,2,1};
int slen = 3;
int index= 0;
index = IsSubArr(array,alen,sub_arr,slen);
cout << "\n\n Place of sub array in long array: " << index;
cout << endl;
return 0;
}
for this line of code:
index = IsSubArr(array,alen,sub_arr,slen);
i get error:
Error 1 error C2782: 'int IsSubArr(T &,int,T &,int)' : template parameter 'T' is ambiguous
please help to resolve this issue ?
Since array[a] and array[b] where a != b are 2 different types, you'll need 2 type templates args.
A work around would be to use pointers.
+ template <class T> int IsSubArr(T* a, int a_len, T* b, int b_len)
+ T* s = a; T*l = b;
You defined the first and the third parameters as references
template <class T> int IsSubArr(T& a, int a_len, T& b, int b_len)
^^^^ ^^^^
and pass as arguments for these parameters two arrays with different types
int array[5] = {9,4,6,2,1};
int sub_arr[3] = {6,2,1};
//...
index = IsSubArr(array,alen,sub_arr,slen);
^^^^^ ^^^^^^^
The first argument has type int[5] and the third argument has type int[3]
So the compiler is unable to deduce the referenced type T.
If you are going to use arrays with the function then you could declare it like
template <class T, size_t N1, size_t N2>
int IsSubArr( T ( &a )[N1], T ( &b )[N2] );
Or you could use pointers instead of the references to arrays
template <class T> int IsSubArr( T *a, size_t a_len, T *b, size_t b_len );
Take into account that this declaration within the function
T& s=a,l=b;
is also wrong. It is equivalent to the following declarations
T& s=a;
T l=b;
That is the first declaration declares a reference to an array while the second declaration declares an array and tries to initialize it with another array. However arrays do not have a copy constructor and the compiler will issue one more error. And you may not reassign a reference.
You should know that there is standard algorithm std::search declared in header <algorithm> that can do the job you want to do with your function.
It's because array and sub_arr are two different types. array is of type int[5] while sub_arr is of type int[3]. The array dimensions are part of the type.
Either change the function to use two different templates arguments, one for each array, or use pointer (e.g. T*)
There's also another error, that you will continue to have if you keep using arrays and two different template arguments, and that is that you can't change references. Once you have assigned to the variable s and l in the function, those can't be made to reference anything else. The latter assignments of the s and l variables will fail because there you try to assign the arrays to each other, which you can not do, you can only copy arrays.
If you use pointers instead, then this won't be a problem.
I want to write copy constructor for a template class. I have this class:
template<int C>
class Word {
array<int, C> bitCells; //init with zeros
int size;
public:
//constructor fill with zeros
Word<C>() {
//bitCells = new array<int,C>;
for (int i = 0; i < C; i++) {
bitCells[i] = 0;
}
size = C;
}
Word<C>(const Word<C>& copyObg) {
size=copyObg.getSize();
bitCells=copyObg.bitCells;
}
}
I have errors with the copy constructor, on the line of intilizeing the size, I get:
"Multiple markers at this line
- passing 'const Word<16>' as 'this' argument of 'int Word::getSize() [with int C = 16]' discards qualifiers [-
fpermissive]
- Invalid arguments ' Candidates are: int getSize() '"
what is wrong with this ?
thank you
I'd write the class like this:
template <std::size_t N>
class Word
{
std::array<int, N> bit_cells_;
public:
static constexpr std::size_t size = N;
Word() : bit_cells_{} {}
// public functions
};
Note:
No need for a dynamic size, since it's part of the type.
No need for special member functions, since the implicitly defined ones are fine.
Initialize the member array to zero via the constructor-initializer-list.
Template parameter is unsigned, since it represents a count.
What's wrong is that your getSize() is not declared const. Make it so:
int getSize() const { return size; }
I'm giving template metaprogramming a go. Here is a simple example I came up with:
template <int n>
struct N
{
static const int k = N<n-2>::k;
};
template<>
struct N<0>
{
static const int k = 0;
};
int main(int, char *[])
{
}
The above works. Note that k is defined as k = N<n-2>::k;
The following fails:
template <int n>
struct N
{
static const int k = N<n-3>::k;
};
template<>
struct N<0>
{
static const int k = 0;
};
int main(int, char *[])
{
cout << N<10>::k;
getchar();
}
Same code, except now k = N<n-3>:k; The compiler complains about the code being too complex. This limit seems fairly arbitrary, is there a way to modify it?
Your original recursion only terminates for even values of the template parameter n. You need two stop cases, for n == 0 and n == 1. In your revised example, you'd need 3 stop cases, or a stop case for n <= 0.
It is said that we'd better use a multi_array builder if we want to use the multi_array more efficiently. However, I'm so new to both template and boost, I tried to copy some code from a book. It looks like this:
class multi_builder : boost::noncopyable
{
public:
typedef boost::multi_array<T,N> array_type;
typedef boost::shared_ptr<array_type > type;
private:
boost::any ext;
public:
multi_builder() : ext(boost::extents){}
~multi_builder(){}
template<std::size_t n>
void dim(std::size_t x)
{
BOOST_STATIC_ASSERT(n >= 0 && n < N);
ext = boost::any_cast<boost::detail::multi_array::extent_gen<n> >(ext) [x];
}
boost::type create(void)
{
return boost::type<array_type>(new array_type(boost::any_cast<boost::detail::multi_array::extent_gen<N> >(ext)));
}
};
However, when I tried to use it in the code like this:
multi_builder<int,2> builder;
builder.dim<0>(2);
builder.dim<1>(2);
BOOST_AUTO(mp,builder.create());
for(int i = 0,v = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
(*mp)[i][j] = v++;
the compiler generates the following errors:
error:invalid use of template-name 'boost::type' without an argument list
error:'class multi_builder<int, 2u>' has no member named 'create'.
error:invalid type in declaration before '=' token
error:'class multi_builder<int, 2u>' has no member named 'create'
error:invalid type argument of 'unary *'
Could someone tell me how to fix the errors?
From the looks of it, the return type of create() lacks a template argument list. I haven't used this Boost component but based on how the value is returned it should probably look like this:
boost::type<array_type> create(void)
There are several problem with the code.
First you are probably missing template parameters for the class (as the other answer pointed out).
Second, create seems to return a smart pointer (shared_ptr) that you define as type in your class (bad name by the away).
This code now compiles and runs: https://godbolt.org/z/qs19eYfso
#include<boost/any.hpp>
#include<boost/multi_array.hpp>
#include<boost/shared_ptr.hpp>
template<class T, std::size_t N>
class multi_builder : boost::noncopyable
{
public:
typedef boost::multi_array<T,N> array_type;
typedef boost::shared_ptr<array_type > type;
private:
boost::any ext;
public:
multi_builder() : ext(boost::extents){}
~multi_builder(){}
template<std::size_t n>
void dim(std::size_t x)
{
BOOST_STATIC_ASSERT(n >= 0 && n < N);
ext = boost::any_cast<boost::detail::multi_array::extent_gen<n> >(ext) [x];
}
type create(void)
{
return type(new array_type(boost::any_cast<boost::detail::multi_array::extent_gen<N> >(ext)));
}
};
int main() {
multi_builder<int,2> builder;
builder.dim<0>(2);
builder.dim<1>(2);
auto mp = builder.create();
for(int i = 0,v = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
(*mp)[i][j] = v++;
}