Class object as template funciton argument - c++

I have an issue with the templates and my knowledge about them is definitely limited.
So I have a class which should store some information:
class Q
{
int integer;
int fractional;
public:
constexpr Q(int i,int f) : integer(i),fractional(f) {}
int get_i() const {return this->integer;}
int get_f() const {return this->fractional;}
constexpr int get_w() {return this->integer + this->fractional;}
friend ostream& operator<<(ostream& os, const Q& q){ os << "Q" << q.integer << "." << q.fractional << " (w:" << q.integer + q.fractional << ")"; return os; }
};
Then I have my templated function. This is just an example but it show the point:
template <Q input_q, Q output_q,const unsigned int X_0_evaluated_bit> void calculate_stuff (const int max_iterations)
{
std::array<Q,input_q.get_w()> input_queue_q;
}
And at the end the main (I'm using the SystemC library) where I generate the constant object Q that I want to use in the function
int sc_main(int argc, char *argv[])
{
constexpr Q Q1_i = Q(1,10);
constexpr Q Q1_o = Q(0,11);
// Number of bits used to address the LUT for the initial value
const unsigned int X_0_evaluated_bit = 5;
// Number of iteration for the Newton-Raphson
const int max_iterations = 2;
calculate_stuff <Q1_i,Q1_o,X_0_evaluated_bit> (max_iterations);
return 0;
}
If I try to compile I get the following error message:
check_ac_one_over.cpp:31:13: error: ‘class Q’ is not a valid type for a template non-type parameter
template <Q input_q, Q output_q,const unsigned int X_0_evaluated_bit> void calculate_stuff (const int max_iterations)
^
check_ac_one_over.cpp:31:24: error: ‘class Q’ is not a valid type for a template non-type parameter
template <Q input_q, Q output_q,const unsigned int X_0_evaluated_bit> void calculate_stuff (const int max_iterations)
^
check_ac_one_over.cpp: In function ‘void calculate_stuff(int)’:
check_ac_one_over.cpp:33:31: error: template argument 2 is invalid
std::array<Q,input_q.get_w()> input_queue_q;
^
check_ac_one_over.cpp:33:46: error: invalid type in declaration before ‘;’ token
std::array<Q,input_q.get_w()> input_queue_q;
^
check_ac_one_over.cpp: In function ‘int sc_main(int, char**)’:
check_ac_one_over.cpp:102:64: error: no matching function for call to ‘calculate_stuff(const int&)’
calculate_stuff <Q1_i,Q1_o,X_0_evaluated_bit> (max_iterations);
^
check_ac_one_over.cpp:102:64: note: candidate is:
check_ac_one_over.cpp:31:76: note: template<<typeprefixerror>input_q, <typeprefixerror>output_q, unsigned int X_0_evaluated_bit> void calculate_stuff(int)
template <Q input_q, Q output_q,const unsigned int X_0_evaluated_bit> void calculate_stuff (const int max_iterations)
^
check_ac_one_over.cpp:31:76: note: template argument deduction/substitution failed:
check_ac_one_over.cpp:102:64: note: invalid template non-type parameter
calculate_stuff <Q1_i,Q1_o,X_0_evaluated_bit> (max_iterations);
^
check_ac_one_over.cpp:102:64: note: invalid template non-type parameter
make: *** [check_ac_one_over.o] Error 1
Now I'm not sure if what I'm trying to do is possible. Does anyone have some ideas how can I make it work ?
Cheers,
Stefano

Does anyone have some ideas how can I make it work ?
Not a great idea, I suppose, but...
The error message is clear:
‘class Q’ is not a valid type for a template non-type parameter
But, in your example, you don't use the full Q object: you use the value of input_q.get_w().
So I suppose that you can pass as template parameter not the full Q object but only the value returned by get_w() that is a int so is a valid as template non-type parameter.
Something (using only the first template parameter; no idea about the use of the other)
template <int input_dim>
void calculate_stuff (const int max_iterations)
{
std::array<Q, input_dim> input_queue_q;
}
that you can call (taking in count that Q1_i and get_w() are constexpr)
calculate_stuff<Q1_i.get_w()> (1);
But observe that
1) get_w() should be also const, not only constexpr
constexpr int get_w() const {return this->integer + this->fractional;}
because a constexpr method isn't automatically const (starting from C++14) but a constexpr object is also const (so can't use get_w() if it isn't defined const)
2) If you want an array of Q as follows
std::array<Q, input_dim> input_queue_q;
the Q type require a constructor without parameters; by example adding default values to your constructor
constexpr Q(int i = 0, int f = 0) : integer(i),fractional(f) {}

I've found a solution. It's not the perfect one but it's quite close. Instead to use the object I'm using the pointer to the object which has become a global variable:
class Q
{
int integer;
int fractional;
public:
constexpr Q(int i = 0,int f = 0) : integer(i),fractional(f) {}
constexpr int get_i() const {return this->integer;}
constexpr int get_f() const {return this->fractional;}
constexpr int get_w() const {return this->integer + this->fractional;}
friend ostream& operator<<(ostream& os, const Q& q){ os << "Q" << q.integer << "." << q.fractional << " (w:" << q.integer + q.fractional << ")"; return os; }
};
template <const Q *input_q,const Q *output_q,const unsigned int X_0_evaluated_bit> void calculate_stuff (const int max_iterations)
{
std::array<Q,input_q->get_w()> input_queue_q;
}
constexpr Q Q1_i = Q(1,10);
constexpr Q Q1_o = Q(0,11);
int sc_main(int argc, char *argv[])
{
// Number of bits used to address the LUT for the initial value
const unsigned int X_0_evaluated_bit = 5;
// Number of iteration for the Newton-Raphson
const int max_iterations = 2;
calculate_stuff <&Q1_i,&Q1_o,X_0_evaluated_bit> (max_iterations);
return 0;
}
Cheers.

Related

C++: Why can't I invoke a template member function of a template parameter type? [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 6 months ago.
I am writing a template function where one of the template parameters is a type with a member function that is itself a template function. When I invoke the template member function and explicitly specify the template parameters, it appears that the code does not compile. This is illustrated in the following minimal example:
This version will compile and run just fine:
#include <iostream>
struct ar_t
{
int data[2];
ar_t(void) {data[0] = 10; data[1] = 17;}
template <const std::size_t idx> int get(void) const {return data[idx];}
};
template <const std::size_t val> struct idx_t {};
template <const std::size_t val> int idx_ar1(const ar_t& ar, const idx_t<val>& idx)
{
return ar.get<val>();
}
int main(int argc, char** argv)
{
ar_t x;
const std::size_t index = 1;
idx_t<index> i;
idx_ar1(x,i);
return 0;
}
whereas this version will not:
#include <iostream>
struct ar_t
{
int data[2];
ar_t(void) {data[0] = 10; data[1] = 17;}
template <const std::size_t idx> int get(void) const {return data[idx];}
};
template <const std::size_t val> struct idx_t {};
template <typename arr_type, const std::size_t val> int idx_ar1(const arr_type& ar, const idx_t<val>& idx)
{
return ar.get<val>();
}
int main(int argc, char** argv)
{
ar_t x;
const std::size_t index = 1;
idx_t<index> i;
idx_ar1(x,i);
return 0;
}
Note the difference in the template parameters for idx_ar1. The error message I get with g++ 11.1 and -std=c++20 is:
main.cc: In function ‘int idx_ar1(const arr_type&, const idx_t<val>&)’:
main.cc:14:24: error: expected primary-expression before ‘)’ token
14 | return ar.get<val>();
| ^
main.cc: In instantiation of ‘int idx_ar1(const arr_type&, const idx_t<val>&) [with arr_type = ar_t; long unsigned int val = 1]’:
main.cc:22:12: required from here
main.cc:14:18: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘long unsigned int’ to binary ‘operator<’
14 | return ar.get<val>();
|
How can I get around this? I require preciesly the behaviour used in the second example. This appears to be a bug in parsing the syntax, or I don't quite have a detailed understanding of the way the member function is being declared.
Try compiling with Clang, too - sometimes it gives better errors than GCC (sometimes worse):
":14:15: error: missing 'template' keyword prior to dependent template name 'get'"

How can I create a vector based on a variable type

I'm using a template function, which the goal is reciever a vector and a function, and return the function type.
template <typename T, typename Function>
auto apply(const std::vector<T>& V, const Function &F){
vector<Function> x; # ERROR HERE
return x;
}
But the IDE give me error (http://coliru.stacked-crooked.com/a/ee6ce2127e013a18):
/usr/local/include/c++/10.2.0/ext/new_allocator.h: In instantiation of 'class __gnu_cxx::new_allocator<double(double)>':
/usr/local/include/c++/10.2.0/bits/allocator.h:116:11: required from 'class std::allocator<double(double)>'
/usr/local/include/c++/10.2.0/bits/stl_vector.h:87:21: required from 'struct std::_Vector_base<double(double), std::allocator<double(double)> >'
/usr/local/include/c++/10.2.0/bits/stl_vector.h:389:11: required from 'class std::vector<double(double), std::allocator<double(double)> >'
main.cpp:10:22: required from 'auto apply(const std::vector<T>&, const Function&) [with T = int; Function = double(double)]'
main.cpp:19:39: required from here
/usr/local/include/c++/10.2.0/ext/new_allocator.h:96:7: error: 'const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::const_pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::const_reference = double (&)(double)]' cannot be overloaded with '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::reference = double (&)(double)]'
96 | address(const_reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
/usr/local/include/c++/10.2.0/ext/new_allocator.h:92:7: note: previous declaration '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::reference = double (&)(double)]'
92 | address(reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
main.cpp: In function 'int main(int, char**)':
main.cpp:19:31: error: conversion from 'vector<double(double),allocator<double(double)>>' to non-scalar type 'vector<double,allocator<double>>' requested
19 | vector<double> r = ::apply(v, seno);
| ~~~~~~~^~~~~~~~~
This is call of the main function.
double seno( double n ) { return sin(n); }
int main( int argc, char* argv[]) {
vector<int> v{ 1, 2, 3, 4, 5 };
vector<double> r = ::apply(v, seno);
cout << r;
return 0;
}
I don't know what I'm doing wrong, so How can I improve this method and pass trough this error?
EDIT: The purpse to generalize the in method insted of using double in the vector is because I want o re-use in another way. So I've generalize the most that I can.
vector<Function> x; // ERROR HERE defines a vector of function pointers. But that's not what you want - you want a vector of the return type of the function. And that's what decltype() is for.
In your apply function, F is the function to be called and T is the type of the values in the vector being passed in. That means T() is the default value of the items in the vector (in this case the default value of int is 0). Then, F(T()) would actually call the function with 0 and return something so decltype(F(T())) tells you the type of the thing returned.
That means you need to write vector<decltype(F(T()))> x; instead.
T() works because the type is int and it is default constructible. As #alterigel said in the comments std::declval<T>() is better when the type is not default constructible.
So vector<decltype(F(std::declval<T>()))> x; might be needed in some situations.
The whole program would look like:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
template <typename T, typename Function>
auto apply(const std::vector<T>& V, const Function &F) {
vector<decltype(F(T()))> x;
for(auto a : V)
x.push_back(F(a));
return x;
}
double seno( double n ) { return sin(n); }
int main( int argc, char* argv[]) {
vector<int> v{ 1, 2, 3, 4, 5 };
vector<double> r = ::apply(v, seno);
for (auto a : r)
cout << a << " ";
return 0;
}
Try it here: https://onlinegdb.com/SknTsVaHO

How can I sum 2 integral template arguments and use the result to instantiate another template?

I am trying to create something like this:
template<int L>
class FP {
public:
int n;
template<int K>
FP<L+K> add(FP<K> a) {
FP<L+K> r;
r.n = n+a.n;
return r;
}
template<int K> int addS(FP<K> a) {
return L+K;
}
};
int main()
{
FP<1> n1;
FP<2> n2;
FP<n1.addS(n2)> n3 = n1.add(n2);
}
I get this from the compiler:
In function 'int main()':
19:16: error: call to non-constexpr function 'int FP::addS(FP) [with int K = 2; int L = 1]'
19:16: error: call to non-constexpr function 'int FP::addS(FP) [with int K = 2; int L = 1]'
19:17: note: in template argument for type 'int'
19:22: error: invalid type in declaration before '=' token
19:33: error: cannot convert 'FP<3>' to 'int' in initialization
19:19: warning: unused variable 'n3' [-Wunused-variable]
In instantiation of 'FP<(L + K)> FP::add(FP) [with int K = 2; int L = 1]':
19:33: required from here
9:5: warning: no return statement in function returning non-void [-Wreturn-type]
How do I fix this?
Generally, I want to save the result to the correct variable but don't want to calculate the correct template value.
The problem is here:
FP<n1.addS(n2)>
because the result of addS is not a constant expression. You must mark it as one
template<int K> constexpr int addS(FP<K> a)
Now constexpr functions yield constant expressions only if their arguments are constant expressions too, so n1 and n2 should also be marked as constexpr.
constexpr FP<1> n1;
constexpr FP<2> n2;
The simpler would be to use auto
auto n3 = n1.add(n2);
else you have to put missing constexpr
template<int L>
class FP {
public:
int n;
template<int K>
FP<L+K> add(FP<K> a) const {
FP<L+K> r;
r.n = n+a.n;
return r;
}
template<int K> constexpr static int addS(FP<K> a) {
return L+K;
}
};
int main()
{
constexpr FP<1> n1;
constexpr FP<2> n2;
FP<n1.addS(n2)> n3 = n1.add(n2);
}
You can use either an auto:
auto n3 = n1.add(n2);
Or slightly change the declaration of addS as it follows:
template<int K>
static constexpr int addS(FP<K> &) {
return L+K;
}
As mentioned by #Jarod42.
Otherwise you can use also a decltype:
decltype(n1.add(n2)) n3 = n1.add(n2);
Or a constexpr support function:
template<int I, int J>
constexpr int f(FP<I> &, FP<J> &) {
return I+J;
}
// ...
FP<f(n1, n2)> n3 = n1.add(n2);
If you don't want to change the definition of addS.

Writing C++ templates to evaluate expression - pointer errors?

I'm writing C++ templates to evaluate expressions with variables. Basically, for a structure like (x+5)*(x-2) it will evaluate the whole expression for any variable x. Here's the relevant code:
.cpp file:
int main(int argc, const char * argv[]){
int x = 5;
typedef MULTIPLY <
ADD < VAR, LIT<5> >,
SUBSTRACT < VAR, LIT<2> >
>
EXPRESSION;
EXPRESSION e;
printf("(x+5)*(x-2) = %d for x=%d", e.eval(x), x);
return 0;
}
header file:
struct VAR{
static inline int eval(int i){ return i; };
};
template<int INT>
struct LIT{
static inline int eval(int i){ return INT; };
};
template<class L, class R>
struct ADD{
static inline int eval(int i){
return L::eval(i) + R::eval(i);
};
};
template<class L, class R>
struct SUBSTRACT{
static inline int eval(int i){
return L::eval(i) - R::eval(i);
};
};
template<class L, class R>
struct MULTIPLY{
static inline int eval(int i){
return L::eval(i) * R::eval(i);
};
};
Which when executed correctly prints out
(x+5)*(x-2) = 30 for x=5
Now, I'm trying to expand this code to accept an array of variables. So
int arr[2] = {1,2};
given to
(x+y)
should put the variables in order and calculate the same thing using the 2 (or any number of) separate values from the array (super simple example).
.cpp file:
int main(int argc, const char * argv[]){
int arr[2] = {1,2};
typedef ADD < VARS<2>, VARS<2> >
EXPRESSION;
EXPRESSION e;
printf("(x+y) = %d\n", e.eval(arr));
return 0;
}
and this is where I get stuck. This is what I have in the header file:
//take an array arr[] of size N
template<int N>
struct VARS{
static inline int eval(int arr[]){
//go for next value
VARS<N-1>::eval(arr+1);
//end return current one
return arr[0];
};
};
// if array size = 0, end execution
template<>
struct VARS<0>{
static inline int eval(int arr[]){ return 0; };
};
template<class L, class R>
struct ADD{
static inline int eval(int i){
return L::eval(i) + R::eval(i);
};
};
but when I try to compile it I get a bunch of errors:
ExpressionTemplate.cpp: In function 'int main(int, const char**)':
ExpressionTemplate.cpp:17:35: error: invalid conversion from 'int*' to 'int' [-fpermissive]
printf("(x+y) = %d\n", e.eval(arr));
^
In file included from ExpressionTemplate.cpp:5:0:
ExpressionTemplate.h:19:23: note: initializing argument 1 of 'static int ADD<L, R>::eval(int) [with L = VARS<2>; R = VARS<2>]'
static inline int eval(int i){
^
ExpressionTemplate.h: In instantiation of 'static int ADD<L, R>::eval(int) [with L = VARS<2>; R = VARS<2>]':
ExpressionTemplate.cpp:17:35: required from here
ExpressionTemplate.h:20:23: error: invalid conversion from 'int' to 'int*' [-fpermissive]
return L::eval(i) + R::eval(i);
^
ExpressionTemplate.h:6:23: note: initializing argument 1 of 'static int VARS<N>::eval(int*) [with int N = 2]'
static inline int eval(int arr[]){
^
ExpressionTemplate.h:20:36: error: invalid conversion from 'int' to 'int*' [-fpermissive]
return L::eval(i) + R::eval(i);
^
ExpressionTemplate.h:6:23: note: initializing argument 1 of 'static int VARS<N>::eval(int*) [with int N = 2]'
static inline int eval(int arr[]){
Any help will be most appreciated :)
Your code is passing an array of ints (which decays into an int*) into your ADD's eval function. But you defined ADD::eval to take a single int. You would need to add another function to ADD to account for the case when you pass an array in, or make a new class (ie. VAR_ADD) to handle this case.

error: invalid conversion from 'int' to 'const char*'

I'm realising a stack data structure. When I call pop function in main function, an error appeared. It phrases like this:
stack.h:13: error: invalid conversion from 'int' to 'const char*'
stack.h:13: error: initializing argument 1 of 'int remove(const char*)
'
And the problem is that I didn't write the remove function with a char or a char* type parameter.
So I hope any of you can help me out of here. Thanks for the help!
template <typename T>
class Stack : public Vector<T> {
public:
Stack () { Vector<T>(); }
T pop() { return remove( this->size() - 1 ); } //stack.h:13
};
template <typename T>
class Vector {
protected:
int _size;
int _capacity;
T* _elem;
void shrink();
public:
T remove ( int r );
int remove ( int lo, int hi );
};
template <typename T>
int Vector<T>::remove ( int lo, int hi ) {
if(lo==hi) return 0;
while( hi < _size ) _elem[ lo++ ] = _elem[ hi++ ];
_size = lo;
shrink();
return hi-lo;
}
template <typename T>
T Vector<T>::remove ( int r ) {
T e = _elem[r];
remove ( r, r + 1 );
return e;
}
in main function,
Stack<int> S;
for(i = 0; i<n; i++) {
S.push(i+1);
}
S.pop();
Since the base class Vector<T> depends on the template parameter, and so has a type that isn't known until the template is instantiated, unqualified name lookup doesn't look there. This means that your unqualified call to remove doesn't resolve to the base-class member, but to some other overload (probably this one).
Write this->remove or Vector<T>::remove to indicate that you're referring to a member.