38 #ifndef VIGRA_UNIT_TEST_HPP 39 #define VIGRA_UNIT_TEST_HPP 51 #include "vigra/config.hxx" 52 #include "vigra/error.hxx" 54 #ifdef VIGRA_NO_WORKING_STRINGSTREAM 56 #define VIGRA_SSTREAM std::strstream 57 #define VIGRA_SSTREAM_STR(s) ((s << char()), std::string(s.str())) 60 #define VIGRA_SSTREAM std::basic_stringstream<char> 61 #define VIGRA_SSTREAM_STR(s) s.str() 84 #elif defined(__CYGWIN__) 86 #define VIGRA_CANT_CATCH_SIGNALS 88 #elif defined(__unix) || defined(unix) 92 #include <sys/signal.h> 97 #define VIGRA_CANT_CATCH_SIGNALS 101 #define VIGRA_TEST_CASE(function) vigra::create_test_case(function, #function "()") 103 #define testCase VIGRA_TEST_CASE 105 #define VIGRA_TEST_SUITE(testsuite) ( new testsuite ) 107 #define VIGRA_CHECKPOINT(message) \ 108 vigra::detail::checkpoint_impl(message, __FILE__, __LINE__) 110 #define VIGRA_ASSERT(predicate) \ 111 vigra::detail::should_impl((predicate), #predicate, __FILE__, __LINE__) 113 #define VIGRA_ASSERT_NOT(predicate) \ 114 vigra::detail::should_impl(!(predicate), "!(" #predicate ")", __FILE__, __LINE__) 116 #define should VIGRA_ASSERT 118 #define shouldNot VIGRA_ASSERT_NOT 120 #define VIGRA_ASSERT_MESSAGE(predicate, message) \ 121 vigra::detail::should_impl((predicate), message, __FILE__, __LINE__) 123 #define shouldMsg VIGRA_ASSERT_MESSAGE 125 #define shouldMessage VIGRA_ASSERT_MESSAGE 127 #define shouldEqual(left, right) \ 128 vigra::detail::equal_impl(left, right, #left " == " #right, __FILE__, __LINE__) 130 #define shouldEqualMessage(left, right, message) \ 131 vigra::detail::equal_impl(left, right, message "\n" #left " == " #right, __FILE__, __LINE__) 133 #define shouldEqualTolerance(left, right, eps) \ 134 vigra::detail::tolerance_equal_impl(left, right, eps, #left " == " #right, __FILE__, __LINE__) 136 #define shouldEqualToleranceMessage(left, right, eps, message) \ 137 vigra::detail::tolerance_equal_impl(left, right, eps, message "\n" #left " == " #right, __FILE__, __LINE__) 139 #define shouldEqualSequence(begin1, end1, begin2) \ 140 vigra::detail::sequence_equal_impl(begin1, end1, begin2, __FILE__, __LINE__) 142 #define shouldEqualSequenceTolerance(begin1, end1, begin2, eps) \ 143 vigra::detail::sequence_equal_tolerance_impl(begin1, end1, begin2, eps, __FILE__, __LINE__) 145 #define VIGRA_ERROR(message) \ 146 vigra::detail::should_impl(false, message, __FILE__, __LINE__) 148 #define failTest VIGRA_ERROR 159 std::string str() {
return VIGRA_SSTREAM_STR(buf); }
161 errstream & operator<<(T t) { buf << t;
return *
this; }
164 inline std::string & exception_checkpoint()
166 static std::string test_checkpoint_;
167 return test_checkpoint_;
171 inline void report_exception( detail::errstream & os,
172 const char * name,
const char * info )
174 os <<
"Unexpected " << name <<
" " << info <<
"\n";
175 if(exception_checkpoint().size() > 0)
177 os <<
"Last checkpoint: " << exception_checkpoint() <<
"\n";
182 unexpected_exception = -1,
184 memory_access_violation = -3,
185 destructor_failure = -4
188 inline bool critical_error(
int i)
189 {
return i <= memory_access_violation; }
191 inline bool unexpected_error(
int i)
194 #ifndef VIGRA_CANT_CATCH_SIGNALS 198 inline long handle_signal_here(
long code)
202 case EXCEPTION_ACCESS_VIOLATION:
203 case EXCEPTION_INT_DIVIDE_BY_ZERO:
204 return EXCEPTION_EXECUTE_HANDLER;
206 return EXCEPTION_CONTINUE_SEARCH;
210 template<
class Generator >
211 int catch_signals( Generator function_object, detail::errstream & err,
int timeout )
217 result = function_object();
219 __except (handle_signal_here(code = GetExceptionCode()))
223 case EXCEPTION_ACCESS_VIOLATION:
224 report_exception(err,
"operating system exception:",
"memory access violation");
225 result = memory_access_violation;
227 case EXCEPTION_INT_DIVIDE_BY_ZERO:
228 report_exception(err,
"operating system exception:",
"integer divide by zero");
229 result = os_exception;
232 report_exception(err,
"operating system exception:",
"unrecognized exception or signal");
233 result = os_exception;
241 #elif defined(__unix) 243 inline jmp_buf & unit_test_jump_buffer()
245 static jmp_buf unit_test_jump_buffer_;
246 return unit_test_jump_buffer_;
249 static void unit_test_signal_handler(
int sig)
251 longjmp(unit_test_jump_buffer(), sig);
254 template<
class Generator >
255 int catch_signals( Generator function_object, detail::errstream & err,
int timeout)
257 volatile int sigtype;
260 #if defined(linux) || defined(__linux) 261 signal(SIGFPE, &unit_test_signal_handler);
262 signal(SIGTRAP, &unit_test_signal_handler);
263 signal(SIGSEGV, &unit_test_signal_handler);
264 signal(SIGBUS, &unit_test_signal_handler);
266 sigset(SIGFPE, &unit_test_signal_handler);
267 sigset(SIGTRAP, &unit_test_signal_handler);
268 sigset(SIGSEGV, &unit_test_signal_handler);
269 sigset(SIGBUS, &unit_test_signal_handler);
274 #if defined(linux) || defined(__linux) 275 signal(SIGALRM, &unit_test_signal_handler);
277 sigset(SIGALRM, &unit_test_signal_handler);
282 sigtype = setjmp(unit_test_jump_buffer());
285 result = function_object();
292 report_exception(err,
"signal:",
"SIGALRM (timeout while executing function)");
293 result = os_exception;
296 report_exception(err,
"signal:",
"SIGTRAP (perhaps integer divide by zero)");
297 result = os_exception;
300 report_exception(err,
"signal:",
"SIGFPE (arithmetic exception)");
301 result = os_exception;
305 report_exception(err,
"signal:",
"memory access violation");
306 result = memory_access_violation;
309 report_exception(err,
"signal:",
"unrecognized signal");
310 result = os_exception;
317 #if defined(linux) || defined(__linux) 323 #if defined(linux) || defined(__linux) 338 template<
class Generator >
339 int catch_signals( Generator function_object, detail::errstream & err ,
int)
341 return function_object();
348 template<
class Generator >
349 int catch_exceptions( Generator function_object, detail::errstream & err,
int timeout )
351 int result = detail::unexpected_exception;
355 result = detail::catch_signals(function_object, err, timeout);
366 catch ( vigra::ContractViolation & ex )
367 { detail::report_exception( err,
"Contract exception: ", ex.what() ); }
368 catch (
const char * ex )
369 { detail::report_exception( err,
"string exception: ", ex ); }
370 catch (
const std::string & ex )
371 { detail::report_exception( err,
"string exception: ", ex.c_str() ); }
374 catch (
const std::bad_alloc & ex )
375 { detail::report_exception( err,
"exception: std::bad_alloc:", ex.what() ); }
377 # if !defined(__BORLANDC__) || __BORLANDC__ > 0x0551 378 catch (
const std::bad_cast & ex )
379 { detail::report_exception( err,
"exception: std::bad_cast:", ex.what() ); }
380 catch (
const std::bad_typeid & ex )
381 { detail::report_exception( err,
"exception: std::bad_typeid:", ex.what() ); }
383 catch (
const std::bad_cast & ex )
384 { detail::report_exception( err,
"exception: std::bad_cast",
"" ); }
385 catch (
const std::bad_typeid & ex )
386 { detail::report_exception( err,
"exception: std::bad_typeid",
"" ); }
389 catch (
const std::bad_exception & ex )
390 { detail::report_exception( err,
"exception: std::bad_exception:", ex.what() ); }
391 catch (
const std::domain_error & ex )
392 { detail::report_exception( err,
"exception: std::domain_error:", ex.what() ); }
393 catch (
const std::invalid_argument & ex )
394 { detail::report_exception( err,
"exception: std::invalid_argument:", ex.what() ); }
395 catch (
const std::length_error & ex )
396 { detail::report_exception( err,
"exception: std::length_error:", ex.what() ); }
397 catch (
const std::out_of_range & ex )
398 { detail::report_exception( err,
"exception: std::out_of_range:", ex.what() ); }
399 catch (
const std::range_error & ex )
400 { detail::report_exception( err,
"exception: std::range_error:", ex.what() ); }
401 catch (
const std::overflow_error & ex )
402 { detail::report_exception( err,
"exception: std::overflow_error:", ex.what() ); }
403 catch (
const std::underflow_error & ex )
404 { detail::report_exception( err,
"exception: std::underflow_error:", ex.what() ); }
405 catch (
const std::logic_error & ex )
406 { detail::report_exception( err,
"exception: std::logic_error:", ex.what() ); }
407 catch (
const std::runtime_error & ex )
408 { detail::report_exception( err,
"exception: std::runtime_error:", ex.what() ); }
409 catch (
const std::exception & ex )
410 { detail::report_exception( err,
"exception: std::exception:", ex.what() ); }
414 detail::report_exception( err,
"unknown exception",
"" );
421 template<
class Generator >
423 int catch_exceptions( Generator function_object, detail::errstream & err)
425 return catch_exceptions(function_object, err, 0);
430 struct unit_test_failed
431 :
public std::exception
433 unit_test_failed(std::string
const & message)
437 virtual ~unit_test_failed() throw()
441 virtual const char * what()
const throw()
443 return what_.c_str();
450 checkpoint_impl(
const char * message,
const char * file,
int line)
452 detail::errstream buf;
453 buf << message <<
" (" << file <<
":" << line <<
")";
454 exception_checkpoint() = buf.str();
458 should_impl(
bool predicate,
const char * message,
const char * file,
int line)
460 checkpoint_impl(message, file, line);
463 detail::errstream buf;
464 buf << message <<
" (" << file <<
":" << line <<
")";
465 throw unit_test_failed(buf.str());
470 should_impl(
bool predicate, std::string
const & message,
const char * file,
int line)
472 should_impl(predicate, message.c_str(), file, line);
475 template <
class Iter1,
class Iter2>
477 sequence_equal_impl(Iter1 i1, Iter1 end1, Iter2 i2,
const char * file,
int line)
479 for(
int counter = 0; i1 != end1; ++i1, ++i2, ++counter)
483 detail::errstream buf;
484 buf <<
"Sequence items differ at index " << counter <<
485 " ["<< *i1 <<
" != " << *i2 <<
"]";
486 should_impl(
false, buf.str().c_str(), file, line);
495 struct ScalarType {};
496 struct VectorType {};
501 typedef VectorType ScalarOrVector;
505 struct FloatTraits<float>
507 typedef ScalarType ScalarOrVector;
508 static float epsilon() {
return FLT_EPSILON; }
509 static float smallestPositive() {
return FLT_MIN; }
510 static float min() {
return -FLT_MAX; }
511 static float max() {
return FLT_MAX; }
515 struct FloatTraits<double>
517 typedef ScalarType ScalarOrVector;
518 static double epsilon() {
return DBL_EPSILON; }
519 static double smallestPositive() {
return DBL_MIN; }
520 static double min() {
return -DBL_MAX; }
521 static double max() {
return DBL_MAX; }
525 struct FloatTraits<long double>
527 typedef ScalarType ScalarOrVector;
528 static long double epsilon() {
return LDBL_EPSILON; }
529 static long double smallestPositive() {
return LDBL_MIN; }
530 static long double min() {
return -LDBL_MAX; }
531 static long double max() {
return LDBL_MAX; }
536 FPT fpt_abs( FPT
arg )
538 return arg < 0 ? -
arg :
arg;
547 FPT safe_fpt_division( FPT f1, FPT f2 )
559 return ((f2 < 1) && (f1 > (f2 * FloatTraits<FPT>::max()))) ?
560 FloatTraits<FPT>::max() :
561 ((((f2 > 1) && (f1 < (f2 * FloatTraits<FPT>::smallestPositive())))
562 || (f1 == 0)) ? 0 : f1/f2 );
571 class close_at_tolerance {
573 explicit close_at_tolerance( FPT tolerance,
bool strong_test =
true )
574 : m_strong_test( strong_test ),
575 m_tolerance( tolerance ) {}
577 explicit close_at_tolerance(
int number_of_rounding_errors,
bool strong_test =
true )
578 : m_strong_test( strong_test ),
579 m_tolerance( FloatTraits<FPT>::epsilon() * number_of_rounding_errors / 2.0 ) {}
581 bool operator()( FPT left, FPT right )
const 583 if (left == 0 && right != 0)
585 return (fpt_abs(right) <= m_tolerance);
587 if (right == 0 && left != 0)
589 return (fpt_abs(left) <= m_tolerance);
591 FPT diff = fpt_abs( left - right );
592 FPT d1 = safe_fpt_division( diff, fpt_abs( right ) );
593 FPT d2 = safe_fpt_division( diff, fpt_abs( left ) );
595 return m_strong_test ? (d1 <= m_tolerance && d2 <= m_tolerance)
596 : (d1 <= m_tolerance || d2 <= m_tolerance);
606 template <
class T1,
class T2,
class T3>
608 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
609 const char * message,
const char * file,
int line, ScalarType)
611 detail::errstream buf;
612 buf << message <<
" [" << left <<
" != " << right <<
"]";
614 close_at_tolerance<T3> fcomparator( epsilon );
615 bool compare = fcomparator ( (T3)left , (T3)right );
616 should_impl(compare, buf.str().c_str(), file, line);
620 template <
class T1,
class T2,
class T3>
622 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
623 const char * message,
const char * file,
int line, VectorType)
625 detail::errstream buf;
626 buf << message <<
" [" << left <<
" != " << right <<
"]";
629 for(
unsigned int i=0; i<epsilon.size(); ++i)
631 close_at_tolerance<typename T3::value_type> fcomparator( epsilon[i] );
632 compare = compare && fcomparator ( left[i] , right[i] );
634 should_impl(compare, buf.str().c_str(), file, line);
637 template <
class T1,
class T2,
class T3>
639 tolerance_equal_impl(T1 left, T2 right, T3 epsilon,
const char * message,
const char * file,
int line)
641 tolerance_equal_impl(left, right, epsilon,
642 message, file, line,
typename FloatTraits<T3>::ScalarOrVector());
645 template <
class Iter1,
class Iter2,
class T>
647 sequence_equal_tolerance_impl(Iter1 i1, Iter1 end1, Iter2 i2, T epsilon,
const char * file,
int line)
649 for(
int counter = 0; i1 != end1; ++i1, ++i2, ++counter)
651 detail::errstream buf;
652 buf <<
"Sequence items differ at index " << counter;
653 tolerance_equal_impl(*i1, *i2, epsilon, buf.str().c_str(), file, line,
typename FloatTraits<T>::ScalarOrVector());
657 template <
class Left,
class Right>
659 equal_impl(Left left, Right right,
const char * message,
const char * file,
int line)
661 detail::errstream buf;
662 buf << message <<
" [" << left <<
" != " << right <<
"]";
663 should_impl(left == right, buf.str().c_str(), file, line);
666 template <
class Left,
class Right>
668 equal_impl(Left * left, Right * right,
const char * message,
const char * file,
int line)
670 detail::errstream buf;
671 buf << message <<
" [" << (
void*)left <<
" != " << (
void*)right <<
"]";
672 should_impl(left == right, buf.str().c_str(), file, line);
676 equal_impl(
double left,
double right,
const char * message,
const char * file,
int line)
678 tolerance_equal_impl(left, right, 1.0e-16, message, file, line);
682 equal_impl(
float left,
float right,
const char * message,
const char * file,
int line)
684 tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
688 equal_impl(
float left,
double right,
const char * message,
const char * file,
int line)
690 tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
694 equal_impl(
double left,
float right,
const char * message,
const char * file,
int line)
696 tolerance_equal_impl(left, right, 1.0e-6f, message, file, line);
703 test_case(
char const * name =
"Unnamed")
704 : name_(name), timeout(0)
707 virtual ~test_case() {}
709 virtual int run() {
return run(std::vector<std::string>()); }
710 virtual int run(std::vector<std::string>
const & testsToBeRun) = 0;
711 virtual void do_init() {}
712 virtual void do_run() {}
713 virtual void do_destroy() {}
715 virtual char const * name() {
return name_.c_str(); }
716 virtual int size()
const {
return 1; }
718 virtual int numberOfTestsToRun(std::vector<std::string>
const & testsToBeRun)
const 720 if(testsToBeRun.empty())
722 for(
unsigned int k=0; k<testsToBeRun.size(); ++k)
723 if(this->name_.find(testsToBeRun[k]) != std::string::npos)
736 std::vector<std::string> testsToBeExecuted(
int argc,
char ** argv)
738 std::vector<std::string> res;
739 for(
int i=1; i < argc; ++i)
740 res.push_back(std::string(argv[i]));
745 :
public detail::test_case
748 using detail::test_case::run;
750 test_suite(
char const * name =
"TopLevel")
751 : detail::test_case(name),
755 virtual ~test_suite()
757 for(
unsigned int i=0; i != testcases_.size(); ++i)
758 delete testcases_[i];
761 virtual void add(detail::test_case * t,
int timeout = 0)
763 t->timeout = timeout;
764 testcases_.push_back(t);
768 virtual int run(std::vector<std::string>
const & testsToBeRun)
770 int size = numberOfTestsToRun(testsToBeRun);
772 std::vector<std::string> testsToBeRunRecursive =
775 : std::vector<std::string>();
778 report_ = std::string(
"Entering test suite ") + name() +
"\n";
780 for(
unsigned int i=0; i != testcases_.size(); ++i)
782 int result = testcases_[i]->run(testsToBeRunRecursive);
783 report_ += testcases_[i]->report_;
785 if(detail::critical_error(result))
787 report_ += std::string(
"\nFatal error - aborting test suite ") + name() +
".\n";
790 else if(detail::unexpected_error(result))
798 detail::errstream buf;
799 buf <<
"\n" << failed <<
" of " << size <<
800 " tests failed in test suite " << name() <<
"\n";
801 report_ += buf.str();
805 detail::errstream buf;
806 buf <<
"All (" << size <<
807 ") tests passed in test suite " << name() <<
"\n";
808 report_ += buf.str();
811 report_ += std::string(
"Leaving test suite ") + name() +
"\n";
816 virtual int numberOfTestsToRun(std::vector<std::string>
const & testsToBeRun)
const 818 if(detail::test_case::numberOfTestsToRun(testsToBeRun) > 0)
821 for(
unsigned int i=0; i != testcases_.size(); ++i)
822 size += testcases_[i]->numberOfTestsToRun(testsToBeRun);
826 virtual int size()
const {
return size_; }
827 virtual std::string report() {
return report_; }
829 std::vector<detail::test_case *> testcases_;
835 struct test_case_init_functor
837 detail::errstream & buf_;
838 test_case * test_case_;
840 test_case_init_functor(detail::errstream & b, test_case * tc)
841 : buf_(b), test_case_(tc)
848 test_case_->do_init();
851 catch(unit_test_failed & e)
853 buf_ <<
"Assertion failed: " << e.what() <<
"\n";
859 struct test_case_run_functor
861 detail::errstream & buf_;
862 test_case * test_case_;
864 test_case_run_functor(detail::errstream & b, test_case * tc)
865 : buf_(b), test_case_(tc)
872 test_case_->do_run();
875 catch(unit_test_failed & e)
877 buf_ <<
"Assertion failed: " << e.what() <<
"\n";
883 struct test_case_destroy_functor
885 detail::errstream & buf_;
886 test_case * test_case_;
888 test_case_destroy_functor(detail::errstream & b, test_case * tc)
889 : buf_(b), test_case_(tc)
896 test_case_->do_destroy();
899 catch(unit_test_failed & e)
901 buf_ <<
"Assertion failed: " << e.what() <<
"\n";
907 template <
class TESTCASE>
908 class class_test_case
912 using test_case::run;
914 class_test_case(
void (TESTCASE::*fct)(),
char const * name)
920 virtual ~class_test_case()
925 virtual void do_init()
927 testcase_ =
new TESTCASE;
932 exception_checkpoint() =
"";
936 detail::errstream buf;
937 buf <<
"\nFailure in initialization of " << name() <<
"\n";
940 buf <<
"Test case failed to clean up after previous run.\n";
945 failed = catch_exceptions(
946 detail::test_case_init_functor(buf,
this), buf, timeout);
951 report_ += buf.str();
957 virtual void do_run()
960 (testcase_->*fct_)();
963 virtual int run(std::vector<std::string>
const & testsToBeRun)
965 if(numberOfTestsToRun(testsToBeRun) == 0)
973 detail::errstream buf;
974 buf <<
"\nFailure in " << name() <<
"\n";
976 failed = catch_exceptions(
977 detail::test_case_run_functor(buf,
this), buf, timeout);
979 report_ += buf.str();
981 if(critical_error(failed))
984 int destruction_failed = destroy();
986 return destruction_failed ?
991 virtual void do_destroy()
999 detail::errstream buf;
1000 buf <<
"\nFailure in destruction of " <<
"\n";
1002 int failed = catch_exceptions(
1003 detail::test_case_destroy_functor(buf,
this), buf, timeout);
1006 report_ += buf.str();
1007 return destructor_failure;
1015 void (TESTCASE::*fct_)();
1016 TESTCASE * testcase_;
1019 class function_test_case
1023 using test_case::run;
1025 function_test_case(
void (*fct)(),
char const * name)
1030 virtual void do_run()
1035 virtual int run(std::vector<std::string>
const & testsToBeRun)
1037 if(numberOfTestsToRun(testsToBeRun) == 0)
1041 exception_checkpoint() =
"";
1043 detail::errstream buf;
1044 buf <<
"\nFailure in " << name() <<
"\n";
1046 int failed = catch_exceptions(
1047 detail::test_case_run_functor(buf,
this), buf, timeout);
1050 report_ += buf.str();
1059 template <
class FCT>
1062 virtual ~test_functor() {}
1063 virtual void operator()() = 0;
1066 {
return FCT(static_cast<FCT const &>(*
this)); }
1069 template <
class FCT>
1070 class functor_test_case
1074 using test_case::run;
1076 functor_test_case(FCT
const & fct,
char const * name)
1081 virtual void do_run()
1086 virtual int run(std::vector<std::string>
const & testsToBeRun)
1088 if(numberOfTestsToRun(testsToBeRun) == 0)
1092 exception_checkpoint() =
"";
1094 detail::errstream buf;
1095 buf <<
"\nFailure in " << name() <<
"\n";
1097 int failed = catch_exceptions(
1098 detail::test_case_run_functor(buf,
this), buf, timeout);
1101 report_ += buf.str();
1112 template <
class TESTCASE>
1115 create_test_case(
void (TESTCASE::*fct)(),
char const * name)
1117 if(*name ==
'&') ++name;
1118 return new detail::class_test_case<TESTCASE>(fct, name);
1123 create_test_case(
void (*fct)(),
char const * name)
1125 if(*name ==
'&') ++name;
1126 return new detail::function_test_case(fct, name);
1129 template <
class FCT>
1132 create_test_case(detail::test_functor<FCT>
const & fct,
char const * name)
1134 if(*name ==
'&') ++name;
1135 return new detail::functor_test_case<FCT>(fct.clone(), name);
1141 #if !defined(__GNUC__) || __GNUC__ >= 3 1145 template <
class E,
class T,
class V>
1147 std::basic_ostream<E,T> & operator,(std::basic_ostream<E,T> & o, V
const & t)
1149 return (o <<
' ' << t);
1152 template <
class E,
class T>
1154 std::basic_ostream<E,T> & operator,(std::basic_ostream<E,T> & o,
1155 std::basic_ostream<E,T> & (*t)(std::basic_ostream<E,T> &))
1164 std::ostream & operator,(std::ostream & o, V
const & t)
1166 return (o <<
' ' << t);
1170 std::ostream & operator,(std::ostream & o,
1171 std::ostream & (*t)(std::ostream &))
R arg(const FFTWComplex< R > &a)
phase
Definition: fftw3.hxx:1009
void add(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r, FixedPoint< IntBits3, FracBits3 > &result)
addition with enforced result type.
Definition: fixedpoint.hxx:561
Definition: accessor.hxx:43