Boost ICL, cardinality of an interval set - c++

In Boost ICL, when I call cardinality() or size() functions on an interval set, the return type is size_t, independent of the type of interval. On 32-bit machines this is a 32-bit unsigned integer. If my intervals, however, are of type int64_t, the cardinality can easily overflow the 32-bit integer. Am I missing something obvious here or is this a serious flaw of this library?
EDIT: example added
The following code compiles and runs without error on 64-bit but not on 32-bit machines, where it throws the assertion.
#include <boost/icl/interval_set.hpp>
int main()
{
boost::icl::interval_set<int64_t> is;
is.add(boost::icl::interval<int64_t>::closed(1, 4294967297LL));
assert(boost::icl::cardinality(is) == 4294967297LL);
}
EDIT: I'm using boost::icl version 1.49.0 on Ubuntu 13.10
EDIT:
This is not particularly a 32/64-bit problem, as the following code wouldn't work on 64-bit either
#include <boost/icl/interval_set.hpp>
int main()
{
boost::icl::interval_set<double> is;
is.add(boost::icl::interval<double>::closed(1, 1.5));
assert(boost::icl::cardinality(is) == 0.5);
}

Reproduced with Boost 1_54 on Ubuntu 14.04.1 LTS
This indeed seems to be a bug. The specialization to fix is
template <class Type>
struct get_size_type<Type, false, false, false>
{
typedef std::size_t type;
};
In icl/type_traits/size_type_of.hpp. Somehow the ICL devs appear not to be testing with -m32 these days.
I've had success replacing it by
// BEGIN SEHE WAS HERE
template <class Type>
struct get_size_type<Type, std::enable_if<not boost::is_arithmetic<Type>::value, mpl::false_>::type::value, false, false>
{
typedef std::size_t type;
};
template <class Type>
struct get_size_type<Type, std::enable_if<boost::is_arithmetic<Type>::value, mpl::false_>::type::value, false, false>
{
typedef typename std::common_type<Type, std::size_t>::type type;
};
// END SEHE WAS HERE
The trait is sadly not very SFINAE friendly, hence the hack to use the first bool template argument for SFINAE. Improvements could be:
use boost type traits only
use integral value deduction from Boost Integer as opposed to common_type<...> for integral types
I've tested this to DoTheRightThing(TM) for interval_set<double> as well as interval_set<uint64_t> on g++ -m32 and -m64.
I'd report this on the mailing list.

Related

Ignored attributes while defining a type for intrinsic function template wrapper

I'm writing a header which makes use of templates to eliminate code duplication while implementing SIMD-based loops using intrinsics. Here's an example that hopefully makes my intention clear:
#include <type_traits> // std::conditional
#include <immintrin.h>
template<class Treal_t>
struct packed_real
{
using type = typename std::conditional<std::is_same<Treal_t, float>::value, __m256, __m256d>::type;
};
template<class Treal_t>
inline typename packed_real<Treal_t>::type loadu256(const Treal_t* ptr)
{
if constexpr (std::is_same<Treal_t, float>::value)
{
return _mm256_loadu_ps(ptr);
}
else if constexpr (std::is_same<Treal_t, double>::value)
{
return _mm256_loadu_pd(ptr);
}
}
Now, when I compile this using the GNU compiler v11.1.0, with flags -std==c++17;-Wall;-Wextra;-Werror, I get the following error:
...: error: ignoring attributes on template argument ‘__m256’ [-Werror=ignored-attributes]
| using type = typename std::conditional<std::is_same<Treal_t, float>::value, __m256, __m256d>::type;
| ^
I'm able to suppress this as follows:
template<class Treal_t>
struct packed_real
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-attributes"
using type = typename std::conditional<std::is_same<Treal_t, float>::value, __m256, __m256d>::type;
#pragma GCC diagnostic pop
};
Therefore, this question has more to do with Should I...? than How can I...?.
Should I proceed this way?
What are the repercussions of tackling intrinsic functions via templates?
Is there a more elegant way of achieving my purpose?
Thanks in advance for your thoughts and inputs.
Update: I observed that although it compiles, the higher-level function that uses the above function fails to do what it's supposed to do. So the question is actually more How can I...? than Should I...?.

MSVC's (seem not perfect) support for constexpr

I am making the naive wheel of type traits's is_base_of. And Here's a minimal demo about my implementation(didn't consider robustness, is_class...).
#include <type_traits>
#include <cstdint>
struct A
{
};
struct B : A
{
};
template
<typename T, typename U>
struct IsBaseOf {
constexpr static bool Test(T* t)
{
return true;
}
constexpr static bool Test(...)
{
return false;
}
constexpr static bool value = IsBaseOf<T,U>::Test(static_cast<U*>(nullptr));
};
int main()
{
static_assert(IsBaseOf<A, B>::value, "Pass");
}
This demo can be compiled by gcc/clang but cannot be compiled by MSVC.
http://rextester.com/ATOC6638
http://rextester.com/IWU81465
When i type it on my laptop's Visual Studio 2015(with update patch 3). It cannot be compiled either, the IDE reminds me that "expression must have constant value" before compiling.
So I wonder how's MSVC support for constexpr, or is my code wrong?
This is almost certainly a bug in MSVC. Especially previous versions had numerous issues with constexpr. Here's just a bunch of them for example. Support for many new features is not all that great yet in MSVC. But it's getting better by the minute. You'll want to always use the latest version to try out this sort of stuff. VisualStudio 2017 compiles this code just fine…
Your code compiles with Visual Studio 2017 (cl version 19.15.26726).
You could try adding /std:c++14 or /std:c++latest compiler switch.

MSVC evaluating context (and erroring) without knowing types

This code fails compilation on MSVC because the static_assert fails:
template<class MyType>
struct Test {
static_assert(MyType(5) != MyType(6), "fails");
};
See: https://godbolt.org/z/vUSMHu
Any ideas how MSVC can evaluate this without even knowing what MyType is?
Even more obscure:
template<class MyType>
struct Test {
static_assert(MyType(5) == MyType(6), "succeeds");
static_assert(!(MyType(5) == MyType(6)), "fails");
};
See: https://godbolt.org/z/3631tu
And instantiating it (i.e. giving MyType a type) also doesn't help:
template<class MyType>
struct Test {
static_assert(MyType(5) != MyType(6), "still fails");
};
Test<int> variable;
See: https://godbolt.org/z/yxF4h0
Or a bit more complex: https://godbolt.org/z/68g6yO
Yes, this strange error happens in MSVC 19.10, but it is already not reproducible in MSVC 19.14 and upward. Demo: https://gcc.godbolt.org/z/635Mxdazd
So it is reasonable to assume that it was just a compiler bug.

Detect if a type exists in C++ [duplicate]

This question already has answers here:
How to detect existence of a class using SFINAE?
(4 answers)
Closed 6 years ago.
I'd need a template which can be called like this:
int x = type_exists< std::vector<int> >::value;
This should set x to 1 if #include <vector> was present (either explicitly or transitively) earlier in the source, otherwise it should set x to 0.
Is it possible to do it in C++? I'm using GCC, so GCC extensions are also fine.
It's also OK to change the call syntax a bit.
It's not OK to run the C++ compiler twice: first just to figure out if we get a compile error.
This is not what you are looking for, but it's as close as you can get to a type_exists trait:
template<class T> struct Void { typedef void type; };
template<class T, class U = void>
struct type_exists { enum { value = 0 }; };
template<class T>
struct type_exists<T, typename Void<T>::type> { enum { value = 1 }; };
Apparently, it works:
static_assert(type_exists<int>::value, "int is not defined");
static_assert(type_exists<SomeNonexistingType>::value, "expected compile-time error");
This does exactly what it is supposed to do. Tested with GCC 5.4.0.
This is not possible, I'm afraid. If we were to use a non defined identifier we would get a compilation error, leading to this code:
int x = type_exists< std::vector<int> >::value;
not to even compile.
Also, the standard doesn't specify any preprocessor directive to be declared within the header file (which is implementation defined instead) for the standard library, therefore you won't be able to detect it even with preprocessor macros.

Is Visual C++ correct when it refuses this template-"dependent" based enum?

Code:
#ifdef _MSC_VER
# pragma warning( disable: 4480 ) // enum base as "nonstandard extension"
#endif
enum ShouldBeFine: char { hola };
enum Choice { a, b, c };
template< Choice c > struct Traits;
template<> struct Traits<a> { typedef char Type; };
template<> struct Traits<b> { typedef wchar_t Type; };
template<> struct Traits<c> { typedef long Type; };
template< Choice c >
struct Blah
{
enum X: typename Traits<c>::Type {};
};
int main()
{}
Only after a Herculean effort to file a bug report with Microsoft, did it occur to me that maybe Visual C++ is correct to refuse it, and g++, which compiles the above fine, is maybe wrong?
EDIT Details: the code fails to compile with Visual C++ 10.0 and with the preview of Visual C++ 11.0. Those compilers spit out some rambling error avalanche beginning with an alleged syntax error. The code compiles fine with MinGW g++ 4.4.1. Dani reports that it compiles fine with CLang. Unfortunately Comeau Online does not support this language feature, so it can't be decided in the way we often did for C++98, just give the code to Comeau.
If I am reading the grammar correctly, you are correct in that this should compile. enum-base is : type-specifier-seq, and type-specifier-seq seems to include pretty much any type name you can think of, including typename Traits<c>::Type. And all three specializations result in Type being integral, which is also required of the enum-base. So That looks kosher to me.
This compiles fine in both clang and g++. In addition, template substitution should occur before the class and the enum inside is created, so it should not matter if its template dependent or not.
This has been fixed in the Visual C++ 11 Beta, released on February 29, 2012.
Note also that the warning you disabled--C4480--has also been fixed, so it is no longer incorrectly emitted in native C++ code when enum class is used.