Templated elipsis constructor C++ - c++

I want to create a templated math vector class. But it says code editor says ambiguous constructor.
I use only header file!!
.h
template<class T>
class MathVec {
private:
std::vector<T> mathVec;
size_t dimension;
public:
MathVec(size_t dim);
MathVec(size_t dim, ...);
MathVec(const MathVec& other);
MathVec();
void print();
};
template<class T>
MathVec<T>::MathVec(size_t dim) {
this->dimension = dim;
this->mathVec = std::vector<T>(dim,0);
}
template<class T>
MathVec<T>::MathVec(size_t dim, ...) {
this->mathVec = std::vector<T>(dim);
this->dimension = dim;
va_list list;
va_start(list, dim);
for (size_t i = 0; i < dim; i++){
this->mathVec[i] = va_arg(list, T);
}
va_end(list);
}
template<class T>
MathVec<T>::MathVec(const MathVec & other) {
this->dimension = other.dimension;
this->mathVec = other.mathVec;
}
template<class T>
MathVec<T>::MathVec() {
this->dimension = 0;
}
template<class T>
void MathVec<T>::print() {
for(int i = 0; i < this->dimension; ++i)
std::cout << this->mathVec[i] << " ";
std::cout << std::endl;
}
In the main.cpp file I use the following code it is working.
MathVec<int> vect(3,1,2,3);
vect.print();
But if I use the following code it is not working
MathVec<int> vect(1);
vect.print();
The error message is the following.
main.cpp:9:18: error: call to constructor of 'MathVec<int>' is ambiguous
mathvec.h:14:9: note: candidate constructor
mathvec.h:15:9: note: candidate constructor
mathvec.h:16:9: note: candidate constructor
I assume that wrong with the ellipsis, but I do not know what can be the problem, and how to solve this issue.

Modern C++ has better way to accomplish that. Create the following constructor:
MathVec( std::initializer_list<T> values )
Usage:
MathVec<int> vect( { 1, 2, 3 } );

My guess would be that the compiler does not know what constructor to call, as these two:
MathVec(size_t dim);
MathVec(size_t dim, ...);
can both be called by
MathVec<int> vect(1);

may I offer some improvements to your design?
There is no reason to pass dimension as a parameter to constructor. I think be better to make it template parameter.
Thus, when you try mix in some expression matrices with different dimensions, you catch error at compile time, not when program executes ;)
Working example:
#include <vector>
#include <iostream>
template <typename T, unsigned int dim>
class Matrix
{
const unsigned int m_dim = dim;
std::vector<T> m_vec;
public:
Matrix(): m_vec(std::vector<T>(m_dim, 0)) {}
virtual ~Matrix() {}
//suppose, we want m_vec be R/O for public
const std::vector<T>& Read() {return m_vec;}
};
int main(int, char **)
{
Matrix<double, 4> m;
for (auto& x : m.Read())
std::cout << x << std::endl;
}

In general I would avoid using C style variadic arguments, check variadic templates instead (C++11) or fold expressions (C++17)

Related

Sleek way to use template function as function argument?

What I really want to do is to compare the performance of different algorithms which solve the same task in different ways. Such algorithms, in my example called apply_10_times have sub algorithms, which shall be switchable, and also receive template arguments. They are called apply_x and apply_y in my example and get int SOMETHING as template argument.
I think the solution would be to specify a template function as template parameter to another template function. Something like this, where template_function is of course pseudo-code:
template<int SOMETHING>
inline void apply_x(int &a, int &b) {
// ...
}
template<int SOMETHING>
inline void apply_y(int &a, int &b) {
// ...
}
template<template_function APPLY_FUNCTION, int SOMETHING>
void apply_10_times(int &a, int &b) {
for (int i = 0; i < 10; i++) {
cout << SOMETHING; // SOMETHING gets used here directly as well
APPLY_FUNCTION<SOMETHING>(a, b);
}
}
int main() {
int a = 4;
int b = 7;
apply_10_times<apply_x, 17>(a, b);
apply_10_times<apply_y, 19>(a, b);
apply_10_times<apply_x, 3>(a, b);
apply_10_times<apply_y, 2>(a, b);
return 0;
}
I've read that it's not possible to pass a template function as a template parameter, so I can't pass APPLY_FUNCTION this way. The solution, afaik, is to use a wrapping struct, which is then called a functor, and pass the functor as a template argument. Here is what I got with this approach:
template<int SOMETHING>
struct apply_x_functor {
static inline void apply(int &a, int &b) {
// ...
}
};
template<int SOMETHING>
struct apply_y_functor {
static inline void apply(int &a, int &b) {
// ...
}
};
template<typename APPLY_FUNCTOR, int SOMETHING>
void apply_10_times(int &a, int &b) {
for (int i = 0; i < 10; i++) {
cout << SOMETHING; // SOMETHING gets used here directly as well
APPLY_FUNCTOR:: template apply<SOMETHING>(a, b);
}
}
This approach apparently works. However, the line APPLY_FUNCTOR:: template apply<SOMETHING>(a, b); looks rather ugly to me. I'd prefer to use something like APPLY_FUNCTOR<SOMETHING>(a, b); and in fact this seems possible by overloading the operator(), but I couldn't get this to work. Is it possible and if so, how?
As it is not clear why you need APPLY_FUNCTION and SOMETHING as separate template arguments, or why you need them as template arguments at all, I'll state the obvious solution, which maybe isn't applicable to your real case, but to the code in the question it is.
#include <iostream>
template<int SOMETHING>
inline void apply_x(int a, int b) {
std::cout << a << " " << b;
}
template<int SOMETHING>
inline void apply_y(int a, int b) {
std::cout << a << " " << b;
}
template<typename F>
void apply_10_times(int a, int b,F f) {
for (int i = 0; i < 10; i++) {
f(a, b);
}
}
int main() {
int a = 4;
int b = 7;
apply_10_times(a, b,apply_x<17>);
apply_10_times(a, b,apply_y<24>);
}
If you want to keep the function to be called as template argument you can use a function pointer as non-type template argument:
template<void(*F)(int,int)>
void apply_10_times(int a, int b) {
for (int i = 0; i < 10; i++) {
F(a, b);
}
}
int main() {
int a = 4;
int b = 7;
apply_10_times<apply_x<17>>(a, b);
apply_10_times<apply_y<24>>(a, b);
}
In any case I see no reason to have APPLY_FUNCTION and SOMETHING as separate template arguments. The only gain is more complex syntax which is exactly what you want to avoid. If you do need to infer SOMETHING from an instantiation of either apply_x or apply_y, this is also doable without passing the template and its argument separately, though again you'd need to use class templates rather than function templates.
PS:
Ah, now I understand what you mean. Yes, apply_10_times() also uses SOMETHING directly. Sorry, I simplified the code in the question too much.
As mentioned above. This does still not imply that you need to pass them separately. You can deduce SOMETHING from a apply_x<SOMETHING> via partial template specialization. This however requires to use class templates not function templates:
#include <iostream>
template <int SOMETHING>
struct foo {};
template <int X>
struct bar {};
template <typename T>
struct SOMETHING;
template <template <int> class T,int V>
struct SOMETHING<T<V>> { static constexpr int value = V; };
int main() {
std::cout << SOMETHING< foo<42>>::value;
std::cout << SOMETHING< bar<42>>::value;
}
What I really want to do is to compare the performance of different
algorithms which solve the same task in different ways.
You should provide more details about that.
Your first step should be get familiar with Google Benchmark. There is as site which provides it online. This tool give proper patterns for your scenario.
In next step you must be aware that in C and C++ there is "as if rule" which allows optimizer do do wonderful things, but makes creation of good performance test extremely difficult. It is easy write test which doesn't measure actual production code.
Here is cppcon talk showing how many traps are hidden when doing a good performance test fro C++ code. So be very very careful.

How do I call template array operator overloading function?

I need to create an adapter C++ class, which accepts an integer index, and retrieves some types of data from a C module by the index, and then returns it to the C++ module.
The data retrieving functions in the C module are like:
int getInt(int index);
double getDouble(int index);
const char* getString(int index);
// ...and etc.
I want to implement an array-like interface for the C++ module, so I created the following class:
class Arguments {
public:
template<typename T> T operator[] (int index);
};
template<> int Arguments::operator[] (int index) { return getInt(index); }
template<> double Arguments::operator[] (int index) { return getdouble(index); }
template<> std::string Arguments::operator[] (int index) { return getString(index); }
(Template class doesn't help in this case, but only template member functions)
The adapter class is no biggie, but calling the Arguments::operator[] is a problem!
I found out that I can only call it in this way:
Arguments a;
int i = a.operator[]<int>(0); // OK
double d = a.operator[]<double>(1); // OK
int x = a[0]; // doesn't compile! it doesn't deduce.
But it looks like a joke, doesn't it?
If this is the case, I would rather create normal member functions, like template<T> T get(int index).
So here comes the question: if I create array-operator-overloading function T operator[]() and its specializations, is it possible to call it like accessing an array?
Thank you!
The simple answer is: No, not possible. You cannot overload a function based on its return type. See here for a similar quesiton: overload operator[] on return type
However, there is a trick that lets you deduce a type from the lhs of an assignment:
#include <iostream>
#include <type_traits>
struct container;
struct helper {
container& c;
size_t index;
template <typename T> operator T();
};
struct container {
helper operator[](size_t i){
return {*this,i};
}
template <typename T>
T get_value(size_t i){
if constexpr (std::is_same_v<T,int>) {
return 42;
} else {
return 0.42;
}
}
};
template <typename T>
helper::operator T(){
return c.get_value<T>(index);
}
int main() {
container c;
int x = c[0];
std::cout << x << "\n";
double y = c[1];
std::cout << y ;
}
Output is:
42
0.42
The line int x = c[0]; goes via container::get_value<int> where the int is deduced from the type of x. Similarly double y = c[1]; uses container::get_value<double> because y is double.
The price you pay is lots of boilerplate and using auto like this
auto x = c[1];
will get you a helper, not the desired value which might be a bit unexpected.

C++ overriding default less than argument for std::set for a particular data type

I have lots of code which creates a std::set<Port*>. Now by default this uses less<Port*> which sorts the set on pointer values. This creates problem in our tool. I want to provide a default comparator my_less for all set<Port*> without having to go and change all the code. So I tried template specialization :
namespace std {
template<> class set<Port*> : public set<Port*, my_less> {};
};
I put this code in a header file already included by all the code files. This works the way I expected that all set<Port*> are now using my_less. The problem is that such specialization is not inheriting constructors. So i get an error if I want to do this :
std::set<Port*> myset_new(myset1.begin(), myset1.end());
set.cpp:53:63: error: no matching function for call to
‘std::set<Port*>::set(std::set<Port*, znl_id_less>::iterator, std::set<Port*, my_less>::iterator)’
set_include.h:27:70: note: candidates are: std::set<Port*>::set()
set_include.h:27:70: note: std::set<Port*>::set(const std::set<Port*>&)
What is a good way to solve this (I can copy the code for constructors but that doesn't seem clean).
Is there any other way to achieve what I am trying to do apart from:
template<> class set<Port*> : public set<Port*, my_less> {};
Since C++11, you can inherit constructors easily with the using-declaration, like this:
namespace std {
template<> class set<Port*> : public set<Port*, my_less> {
public: using set<Port*, my_less>::set;
};
};
Here is my generic solutions to this problem
#include <set>
#include <functional>
#include <iostream>
// structs
struct my_struct
{
int a;
int b;
};
struct my_second_struct
{
int a;
int b;
};
bool operator<(const my_second_struct& m1, const my_second_struct& m2)
{
return m1.b < m2.b;
}
// alias helper
template <typename T>
using custom_comparator_t = std::function<bool(const T, const T)>;
// function to proxy already defined operator to pointers
template<typename T>
auto get_pointer_less()
{
return [](const T* v1, const T* v2) -> bool { return (*v1) < (*v2); };
}
// this is generic solution
template<typename T>
using pointer_set = std::set<T*, custom_comparator_t<T*>>;
// and final config
template<typename T>
auto get_pointer_set()
{
return pointer_set<T>( get_pointer_less<T>() );
}
template<typename T, typename _T>
void fill_and_display(_T& s)
{
s.insert(new T{10, 20});
s.insert(new T{20, 10});
s.insert(new T{0, 100});
s.insert(new T{100, 0});
std::cout << "set: ";
for (const T *ms : s)
std::cout << "( " << ms->a << " ; " << ms->b << " )";
std::cout << std::endl;
}
int main()
{
// First option, create custom less operator inline
std::set<my_struct *, custom_comparator_t<my_struct *>> myset(
[](const my_struct *ms1, const my_struct *ms2) { return ms1->a < ms2->a; }
);
fill_and_display<my_struct>(myset);
// Second option, reuse, already defined less operator
std::set<my_second_struct *, custom_comparator_t<my_second_struct*>> my_second_set(
get_pointer_less<my_second_struct>()
);
fill_and_display<my_second_struct>(my_second_set);
// generic colution for second set
auto my_third_set = get_pointer_set<my_second_struct>();
fill_and_display<my_second_struct>(my_third_set);
return 0;
}

Pass by reference if possible, by value otherwise

I would like to create an instance of my class Matrix using a transformation on another matrix in a template function.
Matrix<T> m(A.tri_lo());
The transformation, here tri_lo() returns a new value, so here my code throws an error :
error C2662: 'Matrix<long double> Matrix<long double>::tri_lo(bool)' : cannot convert a 'this' pointer from 'const Matrix<long double>' to 'Matrix<long double> &'
I tried overloading the constructor for pass-by-value but I couldn't get it to work. Here are my constructors :
Matrix() : data{ {T{}} } {}; // Implemented
Matrix(std::vector<std::vector<T>> _data) : data{ _data } {}; // Implemented
Matrix(unsigned int const lines, unsigned int const cols) { // Implemented
for (unsigned int i = 0; i < lines; i++) { this->data.push_back(std::vector<T>(cols, T())); }
};
template<class T2> Matrix(Matrix<T2> const& other) : data{ other.data } {}; // Implemented
template<class T2> Matrix(Matrix<T2> const other) : data{ other.data } {} // Implemented
Where am I going wrong ?
EDIT : here is the context.
template<class T>
template<class T2>
auto Matrix<T>::operator-(Matrix<T2> const& other) {
assert(this->lines() == other.lines());
assert(this->cols() == other.cols());
decltype(std::declval<T>() - std::declval<T2>()) T3;
Matrix<T3> res(this->lines(), this->cols());
for (unsigned int const i = 0; i < this->lines(); i++) {
for (unsigned int const j = 0; j < this->cols(); i++) {
res[i][j] -= other[i][j];
}
}
return res;
}
Here is the full pastebin. Feel free to include a small code review if needed !
Main issues
There are a lot of issues with your code that Visual Studio didn't catch, but that still break the code.
For example, on lines 86 and 87 of your pastebin file:
decltype (std::declval<T>()*std::declval<T2>()) T3;
Matrix<T3> result = Matrix<T3>::gen_full(this->lines(), other.cols());
You declare a variable called T3, and then try to use it as a template parameter for Matrix. What it should be is:
// Declare T3 as a type
using T3 = decltype (std::declval<T>()*std::declval<T2>());
// Now we can use T3
Matrix<T3> result = Matrix<T3>::gen_full(this->lines(), other.cols());
Or here, in gen_full:
template<class T>
Matrix<T> Matrix<T>::gen_full(unsigned int lines, unsigned int cols, T value){
for(unsigned int i = 0; i < lines; i++) {
std::vector<T> line;
for(unsigned int j = 0; j < cols; j++) {
line.push_back(value);
}
this->data.push_back(line); // Error here
}
};
You're using this, but gen_full is a static function so this isn't available.
We can rewrite it as:
template<class T>
Matrix<T> Matrix<T>::gen_full(unsigned int lines, unsigned int cols, T value){
Matrix<T> m;
for(unsigned int i = 0; i < lines; i++) {
std::vector<T> line;
for(unsigned int j = 0; j < cols; j++) {
line.push_back(value);
}
m.data.push_back(line); // Error here
}
return m;
};
You have the same issue on lines 346 and 348 that you had on 86 and 87:
decltype(std::declval<T>() - std::declval<T2>()) T3;
Matrix<T3> res(this->lines(), this->cols());
We can fix it the same way we did there (with using T3 = decltype(...))
On line 350, you declare i as const, and then you increment it. We can just remove the const and it works.
Other issues
Once we got through the main issues, there are still a few other issues that we can only catch by trying to instantiate the class.
For example, we can use a dummy function to get the compiler to check this for us:
void foo() {
// Forces the compiler to instantiate Matrix<double>
Matrix<double> A;
Matrix<double> B(A.tri_lo());
}
When we try to do this, we get a few cryptic errors, such as here on line 260:
Matrix<T> res(this->lines(), this->cols());
Gcc gives me the error
<source>: In instantiation of 'Matrix<T> Matrix<T>::tri_lo(bool) const [with T = double]':
<source>:365:31: required from here
<source>:262:15: error: passing 'const Matrix<double>' as 'this' argument discards qualifiers [-fpermissive]
262 | Matrix<T> res(this->lines(), this->cols());
| ^~~
What this means is that you're trying to use functions that aren't const (such as lines() and cols()) in a const context (since tri_lo is const)
We can fix this by marking lines() and cols() as const:
// On line 32 and 33
unsigned int cols() const; // Implemented
unsigned int lines() const; // Implemented
And here as well:
// Lines 71 to 75
template<class T>
unsigned int Matrix<T>::cols() const { return this->data.size(); };
template<class T>
unsigned int Matrix<T>::lines() const { return this->data[0].size(); };
What was causing the original problem?
As far as I can tell, the original problem occurred because lines() and cols() weren't marked const.
Conclusion
There were a lot of errors that Visual Studio didn't catch. It's a good idea to use a separate compiler, like gcc or clang, which will catch errors sooner and faster. You can use them online at https://godbolt.org, or you can install them locally.
Here is the original version of your code, along with the errors shown by gcc: https://godbolt.org/z/5eiRNw
And here's the updated version of your code, with the errors fixed (including the one described in your original post): https://godbolt.org/z/vFlyvk
You still need to add an implementation of Matrix<T>::gen_uninitialized, and on line 226, clang warns you that std::vector<T> diag(); is interpreted as the forward-declaration of a function named diag (remove the parenthesis), but everything else looks good!

Calling a functor from a Cuda Kernel [duplicate]

This question already has answers here:
default visibility of C++ class/struct members
(4 answers)
Closed 7 years ago.
I am trying to call a functor from a Cuda Kernel. The functor is given by the programmer and my library uses it to perform some functions and returns the processed array.
Since the functor is in Host Memory Space, I am Copying the object to Device and using the functor in my kernel call.
Error : It says the Functor operator() is inaccessible from the kernel.'
I cannot understand where I am Wrong.
Note : Full Error Message dumped At the end.
Here is the Full Code :
#include <cstdio>
using namespace std;
class my_functor
{
__device__
int operator() (int x)
{
return x*10;
}
};
template <class T,typename Func>
__global__
void for_each_kernel (T* d_v,int N,Func f)
{
int idx = blockIdx.x*blockDim.x + threadIdx.x;
int num_threads = gridDim.x * blockDim.x;
__shared__ T s_x[1024];
for(int i = idx; i < N; i += num_threads)
{
s_x[threadIdx.x] = d_v[i];
// Call The Functor Here
s_x[threadIdx.x] = f (s_x[threadIdx.x]);
d_v[i] = s_x[threadIdx.x];
}
}
template <class T>
class device_vector
{
T *d_v;
int numEle;
public :
device_vector (T *h_v,int N)
{
cudaMalloc ((T**)&d_v,N*sizeof(T));
cudaMemcpy(d_v, h_v, N * sizeof(T), cudaMemcpyHostToDevice);
numEle = N;
}
void set (T data,int index)
{
cudaMemcpy (&d_v[index],&data,sizeof(T),cudaMemcpyHostToDevice);
}
T get (int index)
{
T temp;
cudaMemcpy (&temp,&d_v[index],sizeof(T),cudaMemcpyDeviceToHost);
return temp;
}
// Only Provide Start And End Vertices Fot Which you Want To Do Some Operation
template <typename Func>
void for_each (int start,int end,Func f)
{
Func *new_func;
cudaMalloc (&new_func,sizeof(my_functor));
cudaMemcpy (new_func,&f,sizeof (my_functor),cudaMemcpyHostToDevice);
for_each_kernel<<<26,1024>>> (d_v,end-start+1,*new_func);
}
};
int a[1<<28];
int main ()
{
int N = 1<<28;
my_functor functor;
for (int i=0;i<N;i++)
a[i] = i;
device_vector<int> d (a,N);
d.for_each (0,N-1,functor);
printf ("Getting Element At Index %d : %d \n",100,d.get(100));
return 0;
}
Error Message Dump :
device_vector.cu(40): error: function "my_functor::operator()"
(18): here is inaccessible
detected during:
instantiation of "void for_each_kernel(T *, int, Func) [with T=int, Func=my_functor]"
(107): here
instantiation of "void device_vector<T>::for_each(int, int, Func) [with T=int, Func=my_functor]"
(125): here
1 error detected in the compilation of "/tmp/tmpxft_00005da2_00000000-9_device_vector.cpp1.ii".
You are getting the inaccessible error because my_functor is a class. Class members are, by default, private. If you change your definition of my_functorlike this:
class my_functor
{
public:
__device__
int operator() (int x)
{
return x*10;
}
};
or change it to a struct (note struct members are public by default):
struct my_functor
{
__device__
int operator() (int x)
{
return x*10;
}
};
you might find the code compiles. There are possibly other things wrong with the code, but either of these modifications should remove the source of that particular compilation error.