Boost cpp_dec_float with precision determined at run-time - c++

Normally to create an arbitrary-length data type using Boost's cpp_dec_float, you use:
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<100> > arbFloat;
This is great and all, but it appears that the value for the precision (above it is 100) needs to be constant and determined at compile-time. For example, this code does not compile:
#include <boost/multiprecision/cpp_dec_float.hpp>
int main() {
int custom_precision = 100;
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<custom_precision> > arbFloat;
return 0;
}
and returns the following errors:
In function ‘int main()’:
5:77: error: ‘custom_precision’ cannot appear in a constant-expression
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<custom_precision> > arbFloat;
^
5:93: error: template argument 1 is invalid
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<custom_precision> > arbFloat;
^
5:95: error: template argument 1 is invalid
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<custom_precision> > arbFloat;
^
5:95: error: template argument 2 is invalid
But when int custom_precision is instead constant: const int custom_precision the program compiles fine.
Is there a way to use Boost's cpp_dec_float with the precision determined at run-time, or some way to at least trick it?
I plan to use it with command line parsing, so that I can do something like:
$ ./test_program --precision 500

Related

Array bound set by a function of a generic

I want to set the array length to be the minimum of a constant and a generic like this:
template <int foo> struct Bar{
void my_func( int const (&my_array)[std::min(5, foo)] ) { /*...*/ }
};
This code compiles with clang++ but not g++ and I need my code to work with both. The error g++ gives is: error: array bound is not an integer constant before ']' token. How I can set the length of this array to be the minimum of foo and 5?
When I use clang++ I run into the problem that I can't get anything to bind to my_array. I want to run something like:
int main() {
static const int var[5] = {0,1,2,3,4};
Bar<5> bar;
bar.my_func(var);
}
But when I try to compile this code in clang++ I get: error: reference to type 'const int [*]' could not bind to an lvalue of type 'const int [5]'.
If I get rid of the std::min() stuff and replace it with foo the code compiles and runs fine.
Notes:
To get this code to compile you'll need to #include <algorithm> or similar to access std::min.
I don't think that this being part of a template should matter but when I try similar things with non-template function such as:
const int const_five = 5;
void new_func( int const (&my_array)[std::min(5,const_five)] ) { /*...*/ }
g++ says: error: variable or field 'new_func' declared void and clang++ says candidate function not viable: no known conversion from 'const int [5]' to 'const int [std::min(5, const_five)]' for 1st argument which both look like similar problems.
For int const (&my_array)[std::min(5, foo)] to compile, you need a version of std::min which is constexpr. It is since C++14.
Check the default value for -std of gcc and clang you use (its version-dependant). Ultimately, compile with -std=c++14.
Provided by StoryTeller, a nice working MCVE.
Keep it simple:
[foo < 5 ? foo : 5]

Why does following C++ meta-programming code gives compilation error for N=100 but runs fine for small N?

#include<math.h>
#include<iostream>
using namespace std;
template <int x, int N> struct f{
static const int res = x*(f<x, N-1>::res);
};
template <int x> struct f<x, 0>{
static const int res = 1;
};
int main(){
for(int i=0;i<1000000;++i)
int a = (f<3, 100>::res);
}
If I change f<3, 100> to f<3, 10> code runs fine. But for 100 it gives following error:
.
.
.
k.cpp:7:26: recursively required from ‘const int f<3, 99>::res’
k.cpp:7:26: required from ‘const int f<3, 100>::res’
k.cpp:16:23: required from here
k.cpp:7:19: error: initializer invalid for static member with constructor
k.cpp:7:19: error: ‘f<3, 98>::res’ cannot be initialized by a non-constant expression when being declared
k.cpp: In instantiation of ‘const int f<3, 99>::res’:
k.cpp:7:26: required from ‘const int f<3, 100>::res’
k.cpp:16:23: required from here
k.cpp:7:19: error: initializer invalid for static member with constructor
k.cpp:7:19: error: ‘f<3, 99>::res’ cannot be initialized by a non-constant expression when being declared
k.cpp: In instantiation of ‘const int f<3, 100>::res’:
k.cpp:16:23: required from here
k.cpp:7:19: error: initializer invalid for static member with constructor
k.cpp:7:19: error: ‘f<3, 100>::res’ cannot be initialized by a non-constant expression when being declared
I am new to meta-programming. Though error looks like something related to const but it is not. Can someone please help me understand?
Enable your warnings and read the error output carefully:
warning: integer overflow in expression [-Woverflow]
static const int res = x*(f<x, N-1>::res);
~^~~~~~~~~~~~~~~~~
error: overflow in constant expression [-fpermissive]
static const int res = x*(f<x, N-1>::res);
^~~
For large enough values of N you will have a signed integer overflow, which is undefined behavior in a run-time context and produces a compile-time error in a constant expression.
If I try int a = (f<3, 20>::res); I get
warning C4307: '*': integral constant overflow
Making the int a long long gets over this and gives 3486784401 for f<3, 20>.
This can cope up to f<3, 39> with 4052555153018976267 and then overflows.
Moral: warnings are helpful.

Compilation error while using to_string in c++ program

To get precision and scale of a number i am using this simple program. But while converting number into string it is giving compilation error.
g++ precision.cpp
precision.cpp: In function ‘int main()’:
precision.cpp:6: error: ‘to_string’ was not declared in this scope
When I compile with the -std=c++0x switch I get
g++ precision.cpp -std=c++0x
precision.cpp: In function ‘int main()’:
precision.cpp:6: error: call of overloaded ‘to_string(int)’ is ambiguous
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2604: note: candidates are: std::string std::to_string(long long int)
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2610: note: std::string std::to_string(long long unsigned int)
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2616: note: std::string std::to_string(long double)
The source code looks like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string value = to_string(static_cast<int>(1234));
int precision = value.length();
int scale = value.length()-value.find('.')-1;
cout << precision << " " << scale;
return 0;
}
What is causing this error?
The first error is because std::to_string is a C++11 feature, and GCC by default compiles in C++03 mode.
The second error, when you are using the correct flag, is probably because the support for C++11 in GCC 4.4 (which you seem to be using) is quite minimal. As you can see by the error messages, the compiler shows you the alternatives it have.
By the way, you don't need to cast integer literals to int, they are of type int by default. You might want to cast it to long double though, as that's one of the valid overloads and you seems to want to find the decimal point (the code will not work as expected if there is no decimal point in the string, like when converting an integer).
I recommend to use boost::lexical_cast instead.

Any ideas on how to turn this into a warning?

I'm using this is_enum function to check if a variable is an enum or not.
(See error below)
#include <boost/type_traits/is_enum.hpp>
#include <boost/static_assert.hpp>
template<typename T>
void is_enum(T)
{
BOOST_STATIC_ASSERT(boost::is_enum<T>::value == true);
}
int main()
{
char c = 'a';
is_enum(c);
return 0;
}
This gives me the following error:
-*- mode: compilation; default-directory: "/home/epronk/enums/" -*-
Compilation started at Thu Nov 10 21:20:05
g++ -I /home/epronk/src/boost_1_47_0/ q.cpp
q.cpp: In function ‘void is_enum(T) [with T = char]’:
q.cpp:13: instantiated from here
q.cpp:7: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’
q.cpp:7: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’
Compilation exited abnormally with code 1 at Thu Nov 10 21:20:05
(not sure why g++ (Debian 4.4.5-8) 4.4.5 give me the same error twice)
Is it possible to change this function so it becomes a warning?
For a char you can try to assign 256 to it which results in a overflow error.
edited
Some context: I want to find switch statements like this one.
#define switch(arg) \
is_enums(arg); \
switch(arg)
int main()
{
char c = Red;
switch(c)
{
case Banana: // No warning
break;
case Red:
break;
case Green:
break;
case Blue:
break;
}
return 0;
}
EDIT: Try BOOST_STATIC_WARNING http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/static_warning.html; the code below is my hand-hacked version of doing something similar.
Something like this:
#include <boost/type_traits/is_enum.hpp>
#include <boost/utility.hpp>
#include <boost/static_assert.hpp>
enum AB { A, B };
template<typename T>
typename boost::enable_if_c< boost::is_enum<T>::value,
void >::type is_enum(T) {
}
template<typename T>
typename boost::enable_if_c< !boost::is_enum<T>::value,
void >::type is_enum(T) {
int NOT_AN_ENUMERATION = 1;
}
int main()
{
char c = 'a';
is_enum(c);
is_enum(A);
is_enum(B);
return 0;
}
Will issue a warning about the unused variable if you get your compiler in the right state. With gcc and '-Wall', I get this sort of thing:
thing.cpp: In function 'typename boost::enable_if_c<(! boost::is_enum::value), void>::type is_enum(T) [with T = char]':
thing.cpp:21: instantiated from here
thing.cpp:15: warning: unused variable 'NOT_AN_ENUMERATION'
The error is intentional, since you call a static assert, which means exactly "please trigger a compile-time error if the condition is false".
Your function is strangely named, though: It's not a conditional check whether the variable is an enum, but rather an assertion that it is. You should call it assert_that_var_is_enum_or_die() or something meaningful like that.
A conditional should probably just be:
inline bool is_enum(T) { return boost::is_enum<T>::value; }
If you are using boost, you can use BOOST_STATIC_WARNING defined in header <boost/serialization/static_warning.hpp>. If that does not work on your compiler you can use BOOST_SERIALIZATION_BSW defined in same header. Example code looks like BOOST_SERIALIZATION_BSW(std::is_enum<T>::value,1); where the second parameter is an unique integer. The implementation is conceptually same as BOOST_STATIC_ASSERT except that it uses compiler specific warning such as "negative integer to unsigned conversion" for generation purpose.

Compile error using boost::concept_check

I'm trying to compile simple example to use the boost concept_check
Code is as follow:
#include <vector>
#include <complex>
#include <algorithm>
#include <boost/iterator.hpp>
#include <boost/concept_check.hpp>
template <class foo>
void my_do_sort(std::vector<foo>& v)
{
BOOST_CONCEPT_ASSERT((RandomAccessIterator<foo>));
std::stable_sort(v.begin(),v.end())
}
int main()
{
std::vector<std::complex<double> > v;
v.push_back(std::complex<double>(1,3));
v.push_back(std::complex<double>(2,4));
my_do_sort(v);
}
I then get the following error:
g++ -I~/tmp/BOOST/boost_1_39_0 -g3 -ggdb -pedantic -pedantic-errors -Wall -Werror -O0 --save-temps con1.cpp -o con1
con1.cpp: In function 'void my_do_sort(std::vector<foo, std::allocator<_CharT> >&)':
con1.cpp:11: error: `*' cannot appear in a constant-expression
con1.cpp:11: error: a call to a constructor cannot appear in a constant-expression
con1.cpp:11: error: template argument 1 is invalid
con1.cpp:11: error: template argument 1 is invalid
con1.cpp:11: error: invalid type in declaration before ';' token
make: *** [con1] Error 1
Thanks
If you re-read your code, this shouldn't be surprising. It fails to compile because the concept check fails. You are asserting that foo should implement the RandomAccessIterator concept. The entire point in the library is to produce a compile error (just like the one you're seeing) if the concept check fails.
But foo is not an iterator. it is a std::complex<double>.
It should be BOOST_CONCEPT_ASSERT((RandomAccessIterator<v::iterator>)); as far as I can see.
You want to check that the vector iterator is a random access iterator. Not that the complex numbers stored in the iterator are random access iterators.
This was just compilation issue. I had to use boost namespace.