It seems to me that clang has some problems when using omp collapse in template function.
I've attached a minimal example. Clang (9, 10, 11) can't compile it, while gcc compiles it just fine. Is this a compiler error or is my code doing something illegal?
Making this function non template or dropping the collapse clause makes it compile just fine.
#include <vector>
#include <iostream>
template <typename T>
void test(const std::vector<int> begin_vec) {
#pragma omp parallel for collapse(2)
for (int n = begin_vec.at(0); n < 0; n++) {
for (int h = begin_vec.at(1); h < 1; h++) {
for (int w = begin_vec.at(2); w < 2; w++) {
std::cout << n + h + w << std::endl;
}}}
}
int main() {
test<int>({0,0,0});
}
To compile clang++-10 -fopenmp test.cpp
For me, clang produces the following error
test.cpp:9:16: error: 'this' argument to member function 'at' has type 'const std::vector<int>', but function is not marked const
for (int h = begin_vec.at(1); h < 1; h++) {
^~~~~~~~~
test.cpp:16:3: note: in instantiation of function template specialization 'test<int>' requested here
test<int>({0,0,0});
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/stl_vector.h:1092:7: note: 'at' declared here
at(size_type __n)
^
(I've also tried to use libc++, but it didn't change anything)
Related
I'm trying to adapt an example from Stroustrup C++ 4th Ed Page 1182, to call a function from operator()() vs the bind. Unfortunately, I'm getting a number of compilation errors. The code that worked before is // commented out. Does anyone know how to resolve the errors?
#include <iostream>
#include <random>
#include <map>
#include <functional>
using namespace std;
class rand_int {
public:
rand_int(int lo, int hi) : p{lo,hi}, re{rd()} {}
// int operator()() const { return r(); }
int operator()() const { return
uniform_int_distribution<>{p}(re); }
private:
uniform_int_distribution<>::param_type p;
random_device rd;
default_random_engine re;
// function<int()> r = bind(uniform_int_distribution<>{p}, re);
};
int main()
{
map<int,int> m;
rand_int ri{0,9};
for (int i=0; i < 100; ++i) {
m[ri()]++;
}
for (map<int,int>::iterator it = m.begin();
it != m.end(); ++it)
cout << it->first << ", " << it->second << '\n';
return 0;
}
Compilation:
clang++ -Wall -std=c++11 -pedantic test252.cc && ./a.out
In file included from test252.cc:2:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/random:49:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/random.h:35:
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/uniform_int_dist.h:243:25: error:
no matching function for call to object of type 'const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>'
__ret = __uctype(__urng()) - __urngmin;
^~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/uniform_int_dist.h:166:24: note:
in instantiation of function template specialization
'std::uniform_int_distribution<int>::operator()<const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647> >'
requested here
{ return this->operator()(__urng, _M_param); }
^
test252.cc:12:35: note: in instantiation of function template specialization
'std::uniform_int_distribution<int>::operator()<const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647> >'
requested here
uniform_int_distribution<>{p}(re); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/random.h:323:7: note:
candidate function not viable: 'this' argument has type 'const
std::linear_congruential_engine<unsigned long, 16807, 0, 2147483647>', but
method is not marked const
operator()()
^
This line:
uniform_int_distribution<>{p}(re);
modifies the member re. So the operator() can't be marked const.
You need to do:
int operator()() { // non-const method
return uniform_int_distribution<>{p}(re);
}
Here's a demo.
I try to run a .cpp with a .hpp file in Linux using this command: g++ -c main.cpp but I have this error about calloc():
error: there are no arguments to ‘calloc’ that depend on a template parameter, so a declaration of ‘calloc’ must be available [-fpermissive]
Tr=(T *)calloc(Rows*Colomns, sizeof(T));
In member function ‘T* MyMatrix::Adjoint()’:
MyMatrix.hpp:276:35: error: there are no arguments to ‘calloc’ that depend on a template parameter, so a declaration of ‘calloc’ must be available [-fpermissive]
Temp = (T*)calloc(N*N, sizeof(T));
I noticed that this code works in Microsoft Visual Studio:
#pragma once
#include <iostream>
#include <fstream>
template <typename T>
class MyMatrix {
private:
int Rows;
int Colomns;
T* A; //Matricea
T* Tr; //Transpusa acesteia
float* Inv; //Inversa
public:
MyMatrix(int L, int C)
{
Rows = L;
Colomns = C;
A = (T*)calloc(Rows * Colomns, sizeof(T));
if (A == NULL)
throw("Eroare la alocarea matricii! :(");
}
MyMatrix(T* S, int L, int C)
: MyMatrix(L, C)
{
for (int i = 0; i < Rows * Colomns; ++i)
A[i] = S[i];
}
~MyMatrix() { free(A); }
void Transposed()
{
Tr = (T*)calloc(Rows * Colomns, sizeof(T));
for (int i = 0; i < Colomns; ++i)
for (int j = 0; j < Rows; ++j)
Tr[j * Colomns + i] = A[i * Rows + j];
}
void Inverse()
{ //some code
T* Adj = Adjoint();
Inv = (float*)calloc(Rows * Rows, sizeof(float));
for (int i = 0; i < this->Rows * this->Rows; ++i)
Inv[i] = Adj[i] / (float)Det;
}
};
#endif // MYMATRIX_HPP_INCLUDED
a declaration of ‘calloc’ must be available
The solution is to declare calloc before using it. Since it is a standard function, it must be declared by including the standard header that is specified to declare it.
calloc is declared in the header <stdlib.h>. Note that the .h suffixed headers from the C standard library are deprecated in favour of using the c prefixed headers such as <cstdlib>. However, the c prefixed headers declare the functions in the std namespace which you have failed to use in this case.
So the complete solution is to include <cstdlib>, and use std::calloc.
However, you don't need to use calloc at all. Better solution is to use std::make_unique or std::vector.
As the error message suggests, the g++ compiler used here does not have an implementation wherein the second parameter is a template type i.e. the compiler recognizes the arguments when the second argument is of type int or float because these are the types the compiler knows about its 'calloc' implementation works with these types BUT it does not recognize when the second argument is of a templated type.
Visual Studio used here probably has an implementation which allows template types to be passed to 'calloc'.
Maybe you can try updating the g++ compiler to the latest and then it might support what you are trying to do here.
hope this helps!
In the following program, I have added an explicit return statement in func(), but the compiler gives me the following error:
m.cpp: In function ‘constexpr int func(int)’:
m.cpp:11:1: error: body of constexpr function ‘constexpr int func(int)’ not a return-statement
}
This is the code:
#include <iostream>
using namespace std;
constexpr int func (int x);
constexpr int func (int x)
{
if (x<0)
x = -x;
return x; // An explicit return statement
}
int main()
{
int ret = func(10);
cout<<ret<<endl;
return 0;
}
I have compiled program in a g++ compiler using the following command.
g++ -std=c++11 m.cpp
I have added return statement in function, then Why I got above error?
Prior to C++14, the body of a constexpr function must consist solely of a return statement: it cannot have any other statements inside it. This works in C++11 :
constexpr int func (int x)
{
return x < 0 ? -x : x;
}
In C++14 and up, what you wrote is legal, as are most other statements.
Source.
C++11's constexpr functions are more restrictive than that.
From cppreference:
the function body must be either deleted or defaulted or contain only the following:
null statements (plain semicolons)
static_assert declarations
typedef declarations and alias declarations that do not define classes or enumerations
using declarations
using directives
exactly one return statement.
So you can say this instead:
constexpr int func (int x) { return x < 0 ? -x : x; }
static_assert(func(42) == 42, "");
static_assert(func(-42) == 42, "");
int main() {}
Note that this restriction was lifted in C++14.
Created shared library with below file
example.cpp
#include <iostream>
template <typename T>
T Max (T & a, T & b)
{
return a < b ? b:a;
}
I was trying to use above library in my code
test.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
template int Max <int> (int & a, int & b);
template double Max <double> (double & a, double & b);
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
return 0;
}
when I compiled above code ,getting the following error
test.cpp:4: error: explicit instantiation of non-template ‘int Max’
test.cpp:4: error: expected ‘;’ before ‘<’ token
test.cpp:5: error: explicit instantiation of non-template ‘double Max’
test.cpp:5: error: expected ‘;’ before ‘<’ token
test.cpp: In function ‘int main()’:
test.cpp:11: error: ‘Max’ was not declared in this scope*
I realize this is a trivial example more for academic purpose than anything else. Otherwise I would recommend scrapping the whole thing and just using std::max from the get-go. The standard library provides a wealth of well-specified and tested functionality for the taking; use it unless you have a damn good reason to reinvent the wheel.
If you seriously want to provide a template declaration of a function in a header, and provide the implementation of said-template in a shared object library, you can do it by using explicit instantiation, which it appears you're attempting. However, your attempt appears to be putting said-same in the wrong module.
One way to do it is as follows:
example.hpp
#ifndef MYLIB_EXAMPLE_HPP
#define MYLIB_EXAMPLE_HPP
// define forward declaration here. no implementation
template<class T> T Max(T lhs, T rhs);
#endif
example.cpp
#include "example.hpp"
// provide implementation here
template<class T>
T Max(T lhs, T rhs)
{
return (lhs < rhs) ? rhs : lhs;
}
// explicit instantiations
template int Max<int>(int,int);
template double Max<double>(double,double);
That's it for the library. An example build using clang would be:
clang++ -std=c++11 -Wall -Wextra -pedantic -fPIC -shared -o libexample.so example.cpp
The resulting shared object library exposes the following symbols:
nm libexample.so
0000000000000f50 T __Z3MaxIdET_S0_S0_
0000000000000f20 T __Z3MaxIiET_S0_S0_
U dyld_stub_binder
so as you can see, they're there in the lib. On to the test program that will consume this library:
test.cpp
#include <iostream>
#include "example.hpp"
int main ()
{
int i = 39;
int j = 20;
std::cout << "Max(i, j): " << Max(i, j) << std::endl;
double f1 = 13.5;
double f2 = 20.7;
std::cout << "Max(f1, f2): " << Max(f1, f2) << std::endl;
return 0;
}
We build it as follows (assuming the library is in the local folder):
clang++ -std=c++11 -Wall -Wextra -pedantic -L. -o test -lexample test.cpp
The resulting program, test, produces the following output:
Max(i, j): 39
Max(f1, f2): 20.7
Honestly, there isn't a ton of value in doing it this way, as any future usages of Max that are not provided in your explicit list will result in linker errors (unless that is the intent, in which case it would do exactly what you're looking for).
My recomendations:
Change example.cpp to header a file, Max is a template function
Remove the forward declarations in the code
Remove #include <stdio.h>, unless that really is used somewhere
example.hpp:
template <typename T>
T Max (T& a, T& b)
{
return a < b ? b : a;
}
test.cpp:
#include <iostream>
using namespace std;
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
return 0;
}
The code compiles, and runs as expected using Visual Studio. I understand that never guarantees it will compile/run elsewhere, but I don't understand why in this instance. Perhaps someone can help clarify? The g++ compiler gives me errors at line 45 where the vector of vectors of type RGB are declared:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
/* The following color method uses the provided formula to determine
the float value of each (i,j) coordinate passed as parameters. */
float color (int i, int j)
{
float col = float (((i & 0x08) == 0) ^ ((j & 0x08) == 0));
return col;
}
int main()
{
// The provided RGB object that stores each rgb value:
struct RGB
{
float r;
float g;
float b;
};
int w;
int h;
string filename;
float c; // to store the result from the color method.
cin >> w >> h >> filename;
// A vector of vectors to represent the 2D array:
vector< vector<RGB> > rgb(h, vector<RGB>(w));
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
{
c = color(i, j);
rgb[i][j].r = c;
rgb[i][j].g = c;
rgb[i][j].b = c;
}
ofstream ppmfile;
ppmfile.open (filename);
ppmfile << "P3\n" << w << " " << h << endl;
ppmfile << "255\n";
for (int i = 0; i < h; i++)
{
// The following loop uses integer multiplication to output to the ppm
// file the rgb values converted to integers on the 0-255 scale.
for (int j = 0; j < w; j++)
{
ppmfile << rgb[i][j].r * 255 << " ";
ppmfile << rgb[i][j].g * 255 << " ";
ppmfile << rgb[i][j].b * 255;
if (j != (w-1))
ppmfile << " ";
}
ppmfile << endl;
}
return 0;
}
Here's the full list of errors that pop up in g++:
hw1.cxx: In function 'int main()':
hw1.cxx:45: error: template argument for 'template<class _Alloc> class std::allocator' uses local type 'main()::RGB'
hw1.cxx:45: error: trying to instantiate 'template<class _Alloc> class std::allocator'
hw1.cxx:45: error: template argument 2 is invalid
hw1.cxx:45: error: template argument 1 is invalid
hw1.cxx:45: error: template argument 2 is invalid
hw1.cxx:45: error: invalid type in declaration before '(' token
hw1.cxx:45: error: template argument for 'template<class _Alloc> class std::allocator' uses local type 'main()::RGB'
hw1.cxx:45: error: trying to instantiate 'template<class _Alloc> class std::allocator'
hw1.cxx:45: error: template argument 2 is invalid
hw1.cxx:45: error: initializer expression list treated as compound expression
hw1.cxx:51: error: invalid types 'int[int]' for array subscript
hw1.cxx:52: error: invalid types 'int[int]' for array subscript
hw1.cxx:53: error: invalid types 'int[int]' for array subscript
hw1.cxx:57: error: no matching function for call to 'std::basic_ofstream<char, std::char_traits<char> >::open(std::string&)'
/usr/local/gcc443/lib/gcc/i386-pc-solaris2.10/4.4.3/../../../../include/c++/4.4.3/fstream:696: note: candidates are: void std::basic_ofstream<_CharT, _Traits>::open(const char*, std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]
hw1.cxx:67: error: invalid types 'int[int]' for array subscript
hw1.cxx:68: error: invalid types 'int[int]' for array subscript
hw1.cxx:69: error: invalid types 'int[int]' for array subscript
As I remember C++03 forbids using types with internal linkage in templates.
You should pull the RGB class from the main() function
In C++03 (which is almost certainly what you're getting with g++ 4.4.3) the problem is that local types and types with internal linkage can't be used as template parameters. In this case your RGB class is defined within main and isn't eligible to be used as a parameter to vector.
The restrictions were loosened in C++11 but I can't recall if (function) local types are still forbidden. Visual studio may be using C++11 rules while g++ is not.
I see two errors:
vector< vector<RGB> > rgb(h, vector<RGB>(w));
C++03 does not allow this for a type that is "local" to your function so move the definition out of main().
Also the open function does not take std::string as an argument but const char *. So change
ppmfile.open (filename);
to
ppmfile.open( filename.c_str() );