boost test fails to find custom print - c++

For some reason boost::test can't manage to compile the following code
#define BOOST_TEST_MODULE EPUTests
#include <iostream>
#include <boost/test/unit_test.hpp>
using epu8 = uint8_t __attribute__((vector_size(16)));
std::ostream &operator<<(std::ostream &stream, epu8 const &term) {
stream << "[" << unsigned(term[0]);
for (unsigned i = 1; i < 16; ++i)
stream << "," << unsigned(term[i]);
stream << "]";
return stream;
}
bool failtest(epu8 x) { return false; }
//****************************************************************************//
BOOST_AUTO_TEST_SUITE(EPU8_test)
BOOST_AUTO_TEST_CASE(EPU8_equal) {
epu8 x {};
BOOST_CHECK_PREDICATE(failtest, (x));
}
BOOST_AUTO_TEST_SUITE_END()
//****************************************************************************//
The error message is
In file included from /usr/include/boost/test/tools/floating_point_comparison.hpp:21:0,
from /usr/include/boost/test/tools/old/impl.hpp:21,
from /usr/include/boost/test/test_tools.hpp:46,
from /usr/include/boost/test/unit_test.hpp:18,
from boost_test_epu.cpp:4:
/usr/include/boost/test/tools/detail/print_helper.hpp: In instantiation of 'struct boost::test_tools::tt_detail::print_log_value<__vector(16) unsigned char>':
/usr/include/boost/test/tools/detail/print_helper.hpp:178:5: required from 'std::ostream& boost::test_tools::tt_detail::operator<<(std::ostream&, const boost::test_tools::tt_detail::print_helper_t<T>&) [with T = __vector(16) unsigned char; std::ostream = std::basic_ostream<char>]'
/usr/include/boost/test/utils/lazy_ostream.hpp:66:29: required from 'std::ostream& boost::unit_test::lazy_ostream_impl<PrevType, T, StorageT>::operator()(std::ostream&) const [with PrevType = boost::unit_test::lazy_ostream; T = boost::test_tools::tt_detail::print_helper_t<__vector(16) unsigned char>; StorageT = const boost::test_tools::tt_detail::print_helper_t<__vector(16) unsigned char>&; std::ostream = std::basic_ostream<char>]'
boost_test_epu.cpp:29:1: required from here
/usr/include/boost/test/tools/detail/print_helper.hpp:47:5: error: static assertion failed: Type has to implement operator<< to be printable
BOOST_STATIC_ASSERT_MSG( (boost::has_left_shift<std::ostream,T>::value),
I understand that g++ is complaining that my epu8 type is not printable. However I know it is because changing
BOOST_CHECK_PREDICATE(failtest, (x));
by
std::cout << x << std::endl;
BOOST_CHECK(failtest(x));
works as expected and print by vector variable correctly.
The same error is reported with various version of clang++ and g++
What am I doing wrong ?

BOOST::test requires the console output operator<< to be in the std namespace
namespace std
{
ostream &operator<<(...)
...
}

Related

C++ : how to use spdlog to print custom class pointer?

I am facing a little problem.
I need to use spdlog to log and I have custom classes.
And since, spdlog is able to deal with user defined classes, I could use it log my classes.
But, I my real application, I would like to feed spdlog with a pointer of my class (because there is polymorphism but it's not the point here).
And here goes my troubles.
When I try to feed spdlog with a unique_ptr of my class, it does not compile.
So here a MWE:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <spdlog/spdlog.h> //
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/fmt/ostr.h" // must be included to log object
using namespace std;
struct my_type
{
int i;
template<typename OStream>
friend OStream &operator<<(OStream &os, const my_type &c)
{
return os << "[my_type i=" << c.i << "]";
}
};
template<typename OStream>
OStream &operator<<(OStream &os,const my_type* c)
{
return os << "[my_type i=" << "pointer" << "]";
}
int main() {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
spdlog::logger logger("log_test", console_sink);
logger.set_level(spdlog::level::trace);
auto pLog =std::make_shared<spdlog::logger>(logger); //register it if you need to access it globally
std::unique_ptr<my_type> ptrA(new my_type{12});
pLog->info("user defined type: {}", ptrA); // of course *ptrA simply works, but in my application I have to give ptrA ...
return 0;
}
and I get errors from the compiler gcc:
spdlog/fmt/bundled/core.h:1566:15: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = my_type; _Dp = std::default_delete<my_type>]’
const auto& arg = arg_mapper<Context>().map(val);
spdlog/fmt/bundled/core.h:1567:3: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
static_assert(
spdlog/fmt/bundled/core.h:1184:15: error: use of deleted function ‘fmt::v8::detail::fallback_formatter<T, Char, Enable>::fallback_formatter() [with T = fmt::v8::detail::unformattable; Char = char; Enable = void]’
Formatter f;
^
/spdlog/fmt/bundled/core.h:963:3: note: declared here
fallback_formatter() = delete;
^~~~~~~~~~~~~~~~~~
spdlog/fmt/bundled/core.h:1185:28: error: ‘struct fmt::v8::detail::fallback_formatter<fmt::v8::detail::unformattable, char, void>’ has no member named ‘parse’
parse_ctx.advance_to(f.parse(parse_ctx));
~~^~~~~
spdlog/fmt/bundled/core.h:1186:22: error: ‘struct fmt::v8::detail::fallback_formatter<fmt::v8::detail::unformattable, char, void>’ has no member named ‘format’
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
~~^~~~~~
I guess the problem is comming from the interaction between template<typename OStream> OStream &operator<<(OStream &os,const my_type* c) and spdlog or fmt. So I tried to play a bit around but I am stuck.
Do you have ideas to solve this problem, keeping pLog->info("user defined type: {}", ptrA); ?
The problem comes from the library fmt since version 8 (used by spdlog since version 1.9.0), pointers are no longer supported.
A solution can be to use a wrapper class to store the pointer and precise how fmt should deal with it.

Unable to overload stream extraction operator (>>) in C++

I'm currently trying to understand the basic concepts of operator overloading in C++. Therefore, I created a class wheel that is able to read from a stream by overloading the stream extraction operator >>.
wheel.h
#ifndef WHEEL_H
#define WHEEL_H
#include <cassert>
#include <ostream>
#include <string>
class wheel final {
float rimDiameter;
int productionYear;
std::string velocityIndex = "N/A";
std::string manufacturer = "N/A";
public:
wheel() = default;
wheel( float rimDiameter,
int productionYear,
std::string velocityIndex,
std::string manufacturer
) : rimDiameter{rimDiameter},
productionYear{productionYear},
velocityIndex{velocityIndex},
manufacturer{manufacturer}
{}
~wheel() = default;
friend
auto operator<<(std::ostream &os, const wheel &self) -> std::ostream &;
friend
auto operator>>(std::istream &is, wheel &self) -> std::istream &;
};
#endif
wheel.cpp
#include "wheel.h"
auto operator<<(std::ostream &os, const wheel &self) -> std::ostream & {
return os << " WHEEL" << std::endl
<< " =============================" << std::endl
<< " Rim Diameter: " << self.rimDiameter << "\"" << std::endl
<< " Year of Production: " << self.productionYear << std::endl
<< " Velocity Index: " << self.velocityIndex << std::endl
<< " Manufacutrer: " << self.manufacturer << std::endl;
}
auto operator>>(std::istream &is, wheel &self) -> std::istream & {
char c[3];
is >>
self.rimDiameter >> c[0] >>
self.productionYear >> c[1] >>
self.velocityIndex >> c[2] >>
self.manufacturer;
assert(c[0] == ';' && c[1] == ';' && c[2] == ';');
return is;
}
main.cpp
#include <iostream>
#include "wheel.h"
int main(void) {
wheel w;
std::cin >> w;
std::cout << w;
return 0;
}
To me, it all looks fine, but somehow I keep getting an error telling me that there is no match for 'operator>>' (operand types are 'std::istream {aka std::basic_istream<char>}' and 'float'):
$ make
g++-7 -g -std=c++17 -Wall -Wextra -Wconversion -Wpedantic -c main.cpp
g++-7 -g -std=c++17 -Wall -Wextra -Wconversion -Wpedantic -c wheel.cpp
wheel.cpp: In function 'std::istream& operator>>(std::istream&, wheel&)':
wheel.cpp:16:8: error: no match for 'operator>>' (operand types are 'std::istream {aka std::basic_istream<char>}' and 'float')
is >>
~~~^~
self.rimDiameter >> c[0] >>
~~~~~~~~~~~~~~~~
wheel.cpp:13:6: note: candidate: std::istream& operator>>(std::istream&, wheel&)
auto operator>>(std::istream &is, wheel &self) -> std::istream & {
^~~~~~~~
wheel.cpp:13:6: note: no known conversion for argument 2 from 'float' to 'wheel&'
In file included from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/string:53:0,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/locale_classes.h:40,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/ios_base.h:41,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/ios:42,
from /usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/ostream:38,
from wheel.h:5,
from wheel.cpp:1:
/usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/basic_string.tcc:1465:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> std::basic_istream<_CharT, _Traits>& std::operator>>(std::basic_istream<_CharT, _Traits>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)
operator>>(basic_istream<_CharT, _Traits>& __in,
^~~~~~~~
/usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/basic_string.tcc:1465:5: note: template argument deduction/substitution failed:
wheel.cpp:17:14: note: mismatched types 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>' and 'float'
self.rimDiameter >> c[0] >>
^~~~~~~~~~~
make: *** [wheel.o] Error 1
What am I missing here?
You need to include iostream for input and output like this #include <iostream> and you'll avoid the error.
When outputting, it's the class over which the << operators are defined you always use ostream, but you forgot the case of inputting for >>.
#ifndef WHEEL_H
#define WHEEL_H
#include <cassert>
#include <iostream>
#include <string>
class wheel final {
float rimDiameter;
int productionYear;
std::string velocityIndex = "N/A";
std::string manufacturer = "N/A";
public:
wheel() = default;
wheel( float rimDiameter,
int productionYear,
std::string velocityIndex,
std::string manufacturer
) : rimDiameter{rimDiameter},
productionYear{productionYear},
velocityIndex{velocityIndex},
manufacturer{manufacturer}
{}
~wheel() = default;
friend
auto operator<<(std::ostream &os, const wheel &self) -> std::ostream &;
friend
auto operator >> (std::istream &is, wheel &self) -> std::istream &;
};
#endif /* wheel_hpp */
As #Ext3h pointed out, I am missing the respective include for istream.
Adding #include <istream> to wheel.h resolves the problem.
Thank you very much for you help, would have taken me forever to figure out the issue!

How to create a custom channel in SystemC?

I am trying to create a custom channel in System C. Channel data structure is like following
struct Command {
int cmdType;
int lba;
double timestamp;
int size;
Command() { }
Command(const int c, const int l, const double ts, const int sz) {
make(c, l, ts, sz);
}
void make(const int c, const int l, const double ts, const int sz) {
cmdType = c;
lba = l;
timestamp = ts;
size = sz;
}
inline bool operator ==(const Command & command) const {
return (command.cmdType == cmdType && command.lba == lba
&& command.timestamp == timestamp
&& command.size == size); }
};
ostream and trace functions for this channel are defined as follows
inline ostream & operator <<(ostream & os, const Command command)
{
os << "CmdType " << command.cmdType << endl;
os << "Lba " << command.lba << endl;
os << "Time " << command.timestamp <<endl;
os << "Data " << command.size << endl;
return os;
}
inline void sc_trace(sc_trace_file * &tf, const Command & command, string &name)
{
sc_trace(tf, command.cmdType, name + ".cmdType");
sc_trace(tf, command.lba, name + ".lba");
sc_trace(tf, command.timestamp, name + ".timestamp");
sc_trace(tf, command.size, name + ".size");
}
however I am getting compile error
the error message is very long, however here is the last part
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:312:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:317:6: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_signal_in_if<short int>&, const string&, int)
void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:317:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:322:6: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_signal_in_if<int>&, const string&, int)
void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:322:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:327:6: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_signal_in_if<long int>&, const string&, int)
void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:327:6: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:343:1: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const unsigned int&, const string&, const char**)
sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:343:1: note: candidate expects 4 arguments, 3 provided
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:351:13: note: void sc_core::sc_trace(sc_core::sc_trace_file*, const void*, const string&)
extern void sc_trace( sc_trace_file* tf,
^
/home/user/user/systemc-2.3.1//include/sysc/tracing/sc_trace.h:351:13: note: no known conversion for argument 2 from ‘const Command’ to ‘const void*’
In file included from /home/user/user/systemc-2.3.1//include/sysc/communication/sc_clock_ports.h:31:0,
from /home/user/user/systemc-2.3.1//include/systemc:79,
from /home/user/user/systemc-2.3.1//include/systemc.h:208,
from initiator.h:5,
from initiator.cpp:1:
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1808:1: note: template<class T> void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_inout<T>&, const string&)
sc_trace( sc_trace_file* tf, const sc_inout<T>& port,
^
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1808:1: note: template argument deduction/substitution failed:
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1165:46: note: ‘const Command’ is not derived from ‘const sc_core::sc_inout<T>’
sc_trace( p->tf, iface->read(), p->name );
^
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1791:1: note: template<class T> void sc_core::sc_trace(sc_core::sc_trace_file*, const sc_core::sc_in<T>&, const string&)
sc_trace(sc_trace_file* tf, const sc_in<T>& port, const std::string& name)
^
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1791:1: note: template argument deduction/substitution failed:
/home/user/user/systemc-2.3.1//include/sysc/communication/sc_signal_ports.h:1165:46: note: ‘const Command’ is not derived from ‘const sc_core::sc_in<T>’
sc_trace( p->tf, iface->read(), p->name );
^
appreciate help regarding how to fix this compile issue
here is simple version of the code --- file main.c
#include <stdio.h>
#include <csignal>
#include "systemc.h"
#include "producer.h"
#include "consumer.h"
#include "stdtype.h"
#include <iomanip>
#include <sstream>
using namespace std;
inline ostream & operator <<(ostream & os, const Command command)
{
os << "CmdType " << command.cmdType << endl;
return os;
}
inline void sc_trace(sc_trace_file * tf, const Command & command, const string & name)
{
int* cmdType = (int*) &(command.cmdType);
sc_trace(tf, cmdType, name + ".cmdType");
}
int sc_main(int arg_num, char *arg_vet[])
{
sc_clock clock("clock", 100, SC_PS);
sc_signal <bool> reset;
sc_signal <Command> cmd;
Producer *prd;
prd = new Producer("Producer");
prd->clock(clock);
prd->reset(reset);
prd->cmd_tx(cmd);
Consumer *con;
con = new Consumer("Consumer");
con->clock(clock);
con->reset(reset);
con->cmd_rx(cmd);
sc_trace_file *tf = NULL;
tf = sc_create_vcd_trace_file("trace");
sc_trace(tf, reset, "reset");
sc_trace(tf, clock, "clock");
reset.write(1);
sc_start(100, SC_NS);
reset.write(0);
sc_start(100, SC_NS);
sc_close_vcd_trace_file(tf);
return 0;
}
file consumer.h
#ifndef __CONSUMER_H__
#define __CONSUMER_H__
#include <queue>
#include <systemc.h>
#include "stdtype.h"
using namespace std;
SC_MODULE(Consumer)
{
sc_in_clk clock;
sc_in <bool> reset;
sc_in <Command> cmd_rx;
void ConsumerProcess();
SC_CTOR(Consumer) {
SC_METHOD(ConsumerProcess);
sensitive << reset;
sensitive << clock.pos();
}
};
#endif
file producer.h
#ifndef __PRODUCER_H__
#define __PRODUCER_H__
#include <queue>
#include <systemc.h>
#include "stdtype.h"
using namespace std;
SC_MODULE(Producer)
{
sc_in_clk clock;
sc_in <bool> reset;
sc_out <Command> cmd_tx;
void ProducerProcess();
SC_CTOR(Producer) {
SC_METHOD(ProducerProcess);
sensitive << reset;
sensitive << clock.pos();
}
};
#endif
file consumer.cpp
#include "consumer.h"
void Consumer:: ConsumerProcess(void)
{
cout << "con" << endl;
}
file producer.cpp
#include "producer.h"
void Producer:: ProducerProcess(void)
{
cout << "prd" << endl;
}
and file stdtype.h
#ifndef __STDTYPE_H__
#define __STDTYPE_H__
#include <queue>
#include <systemc.h>
struct Command {
int cmdType;
inline bool operator ==(const Command & command) const {
return (command.cmdType == cmdType); }
};
#endif
to compile above code here is the command line:
g++ -I. -I$SYSTEMC_HOME/include -L. -L$SYSTEMC_HOME/lib-linux64
-Wl,-rpath=$SYSTEMC_HOME/lib-linux64 -I/usr/local/include -L/usr/local/lib -lyaml-cpp -o main main.cpp producer.cpp consumer.cpp -lsystemc -lm
Are you sure that sc_trace function is right?
In order to be successful of your call, overloading function of two types is necessary at least. of course, I didn't think that implicit conversion class.
Anyway, two functions are as below:
sc_trace(sc_trace_file, int, string)
sc_trace(sc_trace_file, double, string)
`
inline void sc_trace(sc_trace_file * &tf, const Command & command, string &name)
{
sc_trace(tf, command.cmdType, name + ".cmdType"); // 1
sc_trace(tf, command.lba, name + ".lba"); // 1
sc_trace(tf, command.timestamp, name + ".timestamp"); // 2
sc_trace(tf, command.size, name + ".size"); // 1
}
found the fix!!!
changed stdtype.h as follows
#ifndef __STDTYPE_H__
#define __STDTYPE_H__
#include <queue>
#include <systemc.h>
#include <iomanip>
#include <sstream>
#include <map>
#include <utility>
#include <vector>
#include <string>
using namespace std;
struct Command {
int cmdType;
inline bool operator ==(const Command & command) const {
return (command.cmdType == cmdType); }
};
inline ostream & operator <<(ostream & os, const Command & command)
{
os << "CmdType " << command.cmdType << endl;
return os;
}
inline void sc_trace(sc_trace_file * tf, const Command & command, const string & name)
{
sc_trace(tf, command.cmdType, name + ".cmdType");
}
#endif
and removed these functions from main.cpp, this fixed the issue and i can trace the channel in vcd file, also added other code to communicate through the channel

Shared library with template parameters

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

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).