Shared library with template parameters - c++

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;
}

Related

Random number generation: compilation errors

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.

C++ Error: no matching function for call to ‘simplex615<arbitraryFunc>::amoeba

I'm trying to implement some C++ code to find the maximum of a function using a simplex algoithm. Unfortunately, I have zero experience in C++.
I'm running into this error and can't seem to find a solution from answers to similar questions.
simplex.cpp: In function ‘int main(int, char**)’:
simplex.cpp:22:25: error: no matching function for call to
‘simplex615::amoeba(arbitraryFunc&, double)’
simplex.amoeba(foo, 1e-7);
There is also warning related to the linked file "simplex615.h"
In file included from simplex.cpp:4:0:
simplex615.h:302:6: note: candidate: void simplex615::amoeba(optFunc&, double) [with F = arbitraryFunc]
void simplex615 ::amoeba(optFunc& foo, double tol) {
simplex615.h:302:6: note: no known conversion for argument 1 from ‘arbitraryFunc’ to ‘optFunc&
simplex.cpp
#include <vector>
#include <cmath>
#include <iostream>
#include "simplex615.h"
#define ZEPS 1e-10
// function object used as an argument
class arbitraryFunc {
public:
double operator() (std::vector<double>& x) {
// f(x0,x1) = 100*(x1-x0^2)^2 + (1-x0)^2
return 100*(x[1]-x[0]*x[0])*(x[1]-x[0]*x[0])+(1-x[0])*(1-x[0]);
}
};
int main(int main, char** argv) {
double point[2] = {-1.2, 1};
arbitraryFunc foo;
// initial point to start
// WILL BE DISCUSSED LATER
simplex615 <arbitraryFunc> simplex(point, 2); // create a simplex
simplex.amoeba(foo, 1e-7); // optimize for a function
// print outputs
std::cout << "Minimum = " << simplex.ymin() << ", at ("
<< simplex.xmin()[0] << ", " << simplex.xmin()[1]
<< ")" << std::endl;
return 0;
}
simplex615.h
template <class F> // F is a function object
void simplex615 <F>::amoeba(optFunc& foo, double tol) {
evaluateFunction(foo);
while(true) {
evaluateExtremes();
prepareUpdate();
if ( check_tol(Y[idxHi],Y[idxLo],tol) ) break;
updateSimplex(foo, -1.0); // reflection
if ( Y[idxHi] < Y[idxLo] ) {
updateSimplex(foo, -2.0); // expansion
}
else if ( Y[idxHi] >= Y[idxNextHi] ) {
if ( !updateSimplex(foo, 0.5) ) {
contractSimplex(foo);
}
}
}
}
simplex615.h
class optFunc {
public:
virtual double operator() (std::vector<double>& x) = 0;
};
Link to the complete files simplex.cpp and simplex.h: Source code
Any help will be appreciated. Thanks.
It seems to me that in your simplex615.h you have forgotten to use 'class F' in amoeba method. Just replace optFunc with F and it should fix the problem.
template <class F> // F is a function object
void simplex615 <F>::amoeba(F& foo, double tol) {
...
}
A template class argument in C++ defines a general type which can be replaced when using the template.
Also from this example, you can remove the declaration of optFunc from the header file.

Grammar of __PRETTY_FUNCTION__

GCC offers __PRETTY_FUNCTION__ (6.48 Function Names as Strings) which is a string with function name.
For example following program:
#include <iostream>
#include <string>
namespace n1
{
namespace n2
{
template<typename T>
class t1
{
public:
template<typename R>
R f(T const&) const noexcept
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return {};
}
};
}
}
int main()
{
n1::n2::t1<std::string>{}.f<double>(std::string{});
}
when build with
g++ -Wall -Wextra -Wpedantic -std=c++14
on my g++ (GCC) 7.2.0 (MinGW), produces following output:
R n1::n2::t1<T>::f(const T&) const [with R = double; T = std::__cxx11::basic_string<char>]
Now, the question is - where can I find grammar corresponding to this string. Obviously it is C++ based since there are components (identifiers for example) that come from C++, however entire string definitly is not a valid C++ so it cannot be found in C++ specification.
Is it specified anywhere?
I guess it is not (after all above mentioned link doesn't say it...). However, maybe at least it could be read from sources - where would I find those?

Understanding templates in c++

I am trying run the following program, But it generates compilation error:
#ifndef TEMPLATE_SUM_H_
#define TEMPLATE_SUM_H_
template<typename T>
class sum
{
public:
sum() {
val_1 = 0;
val_2 = 0;
}
sum(T a, T b) {
val_1 = a;
val_2 = b;
}
friend std::ostream& operator<<(std::ostream &, const sum<> &);
private:
T val_1, val_2;
T result() const;
};
#endif
Source file:
include <iostream>
#include "inc/sum.h"
template<typename T>
T sum<T>::result() const {
return (val_1 + val_2);
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const sum<T>& obj) {
//std::ostream& operator<<(std::ostream& os, sum<T>& obj) {
os << obj.result();
return os;
}
int main()
{
sum<int> int_obj(15, 15);
sum<float> float_obj(5.2, 3.5);
std::cout << "result of int = " << int_obj << std::endl;
std::cout << "result of float = " << float_obj << std::endl;
return 0;
}
Compiling with g++ (4.4.3) it generates following error:
In file included from template.cpp:2:
inc/sum.h:18: error: wrong number of template arguments (0, should be 1)
inc/sum.h:5: error: provided for ‘template<class T> class sum’
template.cpp: In function ‘std::ostream& operator<<(std::ostream&, const sum<T>&) [with T = int]’:
template.cpp:20: instantiated from here
template.cpp:5: error: ‘T sum<T>::result() const [with T = int]’ is private
template.cpp:12: error: within this context
template.cpp: In function ‘std::ostream& operator<<(std::ostream&, const sum<T>&) [with T = float]’:
template.cpp:21: instantiated from here
template.cpp:5: error: ‘T sum<T>::result() const [with T = float]’ is private
template.cpp:12: error: within this context
1) Can Anyone please help me in identifying the error ?
Also Please suggest some links where I can find brief absolute details on how to use templates in c++.
2) I read that templatized func/classes declared in header file, and defined separately are prone to linking error. Can anyone explain/elaborate this ?
Is there any possibility of linking error in above example ?
The statement is as below:
"If a template or inline function is declared in a .h file, define it in that same file. The definitions of these constructs must be included into every .cpp file that uses them, or the program may fail to link in some build configurations."
This example can be done in some more easy way, without using overloaded operator etc. But I am trying to learn/practising templates and experimenting some features.
You need to have a separate template definition for the friend function declaration:
template<typename U>
friend std::ostream& operator<<(std::ostream &, const sum<U> &);
friend declarations do not inherit the template parameters of the enclosing class.
A simple sample source, to get started;
Calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H
template <class TYPE>
class Calculator{
public:
Calculator();
TYPE Sum(TYPE param1, TYPE param2);
};
/**
* To avoid template related compilation error
* when templates are used in header and source files
*
* This class file has been removed from the project-source file.
* However, is present in the project folder
* Gets compiled with the header-file (being included)
*/
#include "Calculator.cpp"
#endif
Calculator.cpp
#include <iostream>
using namespace std;
#include "Calculator.h"
template <class TYPE>
Calculator<TYPE>::Calculator()
{
}
template <class TYPE>
TYPE Calculator<TYPE>::Sum(TYPE param1, TYPE param2){
cout << "Calculator::sum" << endl;
cout << param1 <<endl;
cout << param2 <<endl;
TYPE result = param1 + param2 ;
return result;
}
Main.cpp
#include <iostream>
using namespace std;
#include "Calculator.h"
int main(int argc, const char * argv[]) {
cout << "Hello, Calculator!\n";
Calculator<int> cObj;
int out = cObj.Sum(2,3);
cout << "out : " << out << endl;
Calculator<string> cObjS;
string outS = cObjS.Sum("A", "B");
cout << "outS : " << outS << endl;
cout << "Bye, Calculator!\n";
return 0;
}
Additionally, you can refer to the post, to know about how to keep the template source and header contents, and knowing about how to fix the compilation and linker issues (with reasons).

constexpr different exception specifier when splitting definition and declaration

I have the following test piece of code tested on gcc 4.7.2:
#include <iostream>
#include <type_traits>
#ifdef REMOVE_CONSTEXPR_NOEXCEPT
# define CONSTEXPR_NOEXCEPT
#else
# define CONSTEXPR_NOEXCEPT noexcept
#endif
class ConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static constexpr unsigned int Int(unsigned int i) CONSTEXPR_NOEXCEPT
#ifndef SPLIT_CONSTEXPR_DECLARATION
{
return i;
}
#else
;
#endif
};
#ifdef SPLIT_CONSTEXPR_DECLARATION
constexpr unsigned int ConstExpr::Int(unsigned int i) CONSTEXPR_NOEXCEPT {
return i;
}
#endif
class NoConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static unsigned int Int(unsigned int i) noexcept;
};
// It's OK on normal functions
inline unsigned int NoConstExpr::Int(unsigned int i) noexcept {
return i;
}
int main()
{
std::cout << "ConstExpr: " << std::integral_constant<unsigned int,
ConstExpr::Int(5)>::value << std::endl;
std::cout << "NoConstExpr: " << NoConstExpr::Int(5) << std::endl;
}
I get the following compilation output:
[matt test] g++ -std=c++11 main.cpp && ./a.out
ConstExpr: 5
NoConstExpr: 5
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION && ./a.out
main.cpp:28:55: error: declaration of ‘static constexpr unsigned int ConstExpr::Int(unsigned int)’ has a different exception specifier
main.cpp:17:33: error: from previous declaration ‘static constexpr unsigned int ConstExpr::Int(unsigned int) noexcept (true)’
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION -DREMOVE_CONSTEXPR_NOEXCEPT && ./a.out
ConstExpr: 5
NoConstExpr: 5
So my question is: Is it part of the C++11 spec to be able to split the definition and declaration of constexpr functions or is this a gcc bug?
Looks like the gcc bug solves this in 4.8.1