How to implement own function to std::vector? - c++

I would like to add a function that returns the .size() value as an integer, instead of unsigned integer.
Edit: Due to comments, i explain more detailed:
I have code:
int something = 3;
if(arr.size() > something)
Which will produce compiler warning, and i dislike adding (int) to every place where i have this.
So, a solution i thought it would be nice to have sizei() function:
int something = 3;
if(arr.sizei() > something)
Which wouldnt produce a warning.
So, im not wanting to create a separate function, but a function in the std::vector itself.
Edit: Seems like the only way to do this is to create another function, such as:
template <typename T>
inline int sizei(const T &arr){
return (int)arr.size();
}
On the positive side: this doesnt seem to increase my executable size at all.

First of all, why would you want that? I don't see any reason, or advantage:
Anyway, you can do this:
template<typename T>
int size(const std::vector<T> &v) { return (int) v.size(); }
//use
std::vector<int> ints;
//...
int count = size(ints);
Still I don't see any point in doing that. You can simply write:
int count = (int) ints.size();
But I would still say its not better than the following :
size_t count = ints.size(); //don't prefer anything over this. Always use size_t
Advice: avoid using int for size. Prefer size_t.
As for the edit in your question. Why don't you use size_t as:
size_t something = 3;
if(arr.size() > something)
No warning. In my opinion, if you choose the data type consistently throughout your program, you wouldn't come across a situation when you've to compare int with size_t which is defined as unsigned integral type.
Or if there is some legacy code which you've to work with, and which use int for size, then I think its better to use explicit cast when you need it, instead of adding a function in the framework itself, which hides the potential problem:
int something = /*some legacy code API call or something */;
if(arr.size() > (size_t) something)
//or even better;
size_t something = (size_t) /*some legacy code API call or something */;
if(arr.size() > something)

As a rule, in C and C++ you should never use an unsigned type such as size_t to restrict the domain. That's because (1) these languages provide no range checking, and (2) they do provide unreasonable implicit promotions. No range checking means (1) no advantage, and unreasonable implicit promotions means (2) very undesirable disadvantages, so it's plain stupid thing to do: no advantage, very undesirable disadvantages.
However, the standard libraries for these languages do that. They do it for historical reasons only, caught irreversibly in early decisions which at one time made sense. This has both extremely silly consequences such as C99 requiring 17 (!) bits for ptrdiff_t, and it has the aforementioned extremely undesirable consequences such as using inordinately much time on hunting down bugs resulting from implicit promotions (etc.). For example, in C++ you are practically guaranteed that std::string( "bah!" ).length() < -5 – which can easily trip you up and anyway is as silly as it is possible to design.
Now, you can't infuse new member functions in std::vector, but you can add a freestanding function. A good name is countOf. Template it so that it can be applied to just about anything (raw arrays, vectors, etc.).
The triad of functions startOf, endOf and countOf were, as far as I know, first identified by Dietmar Kuehl. C++0x will have std::begin and std::end, but AFAIK no corresponding std::size. In the meantime you can just define this support, which allows you to treat any kinds of container plus raw arrays the same.
An example implementation & further discussion is provided at my blog.
EDIT Adding some code, because it's requested in the comments.
Detection of suitable iterator type:
template< typename Type >
struct It
{
typedef typename Type::iterator T;
};
template< typename Type >
struct It< Type const >
{
typedef typename Type::const_iterator T;
};
template< typename ElemType, Size N >
struct It< ElemType[N] >
{
typedef ElemType* T;
};
And the countOf, startOf and endOf functions, using that deduced iterator type:
template< typename T >
inline Size countOf( T const& c ) { return static_cast<Size>( c.size() ); }
template< typename T, Size N >
inline Size countOf( T (&)[N] ) { return N; }
template< typename T >
inline typename It<T>::T startOf( T& c ) { return c.begin(); }
template< typename T, Size N >
inline T* startOf( T (&a)[N] ) { return a; }
template< typename T >
inline typename It<T>::T endOf( T& c ) { return c.end(); }
template< typename T, Size N >
inline T* endOf( T (&a)[N] ) { return a + N; }
where Size is a typedef for ptrdiff_t.
Note: in 64-bit Windows int (and even long) is 32-bit. Hence, int is in general not sufficient for a really large array. ptrdiff_t is guaranteed to be able to represent the difference between any two pointers, when that difference is well-defined.
Cheers & hth.

You can derive from vector as follows:
template<typename T>
class my_vector : public vector<T>
{
// missing constructors!
int size() const
{
if (vector<T>::size() > INT_MAX)
throw std::range_error("too many elements in vector");
return (int) vector<T>::size();
}
};
The down-side is that you'll have to define and forward constructors yourself.

I would favor using an explicit cast to int instead of a function: static_cast<int> (v.size()). Even better would be to always use size_t when dealing with memory sizes. For example, favor for (size_t i=0; i < v.size(); ++i) over for (int i=0; i < (int) v.size(); ++i). Use the right type for the job. You should not be comparing std::vector sizes with a signed type.
See the following references for why you should prefer size_t to int:
Using size_t appropriately can improve the portability, efficiency, or readability of your code. Maybe even all three.
unsigned int vs. size_t
Is it good practice to use size_t in C++?
When should I use std::size_t?

Quick answer for .size() is: no. For vectors, the possibilities are its storage value and the alloc method (default new/delete, not normally overridden) along with methods that utilize InputIterator.
Most are going to ask why would you want a different size_t. If it's just the annoy warnings, you can cast or use unsigned integers to iterate/check against size(). (If it's a lot of code, you going to have to find/replace)... If it is handling empty conditions, you could wrap the vector in a class with some smarts. As an aside, since I don't know your problem at hand, a good place to look for ideas and already implemented features is std library's algorithms such as sort, for_each, find, and lots more.
For std algorithms, see: http://www.sgi.com/tech/stl/table_of_contents.html

While #Nawaz, in my opinion, provided the most appropriate answer, if you really want to add an additional member to std::vector<> it isn't really possible. #zvrba provided the only way that could be accomplished, but as stated in the comments there the std container types do not have virtual destructors and therefore are not meant to be subclassed from.
However, you could implement a new type of vector using a container adaptor, like this:
template <class T>
class my_vector
{
public:
int size_i() const
{
return static_cast<int>(container_.size());
}
private:
std::vector<T> container_;
};
The drawback here is that you have to explicitly expose the functions of the container that you actually need to support. If you are using 'std::vector' normally throughout your code, this would likely be a significant change. See 'std::queue' for an implementation example of a container adaptor.

Related

Nice syntax to get sized reference to vector's/array's data?

I'm wondering if there's any std:: function to get a sized pointer/reference to a vector/array's underlying data? Something better than:
const size_t(&asArray1)[N] = *(size_t(*)[N]) vec.data();
const size_t(&asArray2)[arr.size()] = *(size_t(*)[arr.size()]) arr.data();
Clarification - something I could pass to the below:
template<size_t N>
void foo(size_t(&sizedArray)[N]) {}
Update -- SOLUTION:
Use helper functions defined once, that do the appropriate casting and leave the call-site cleaner... See my answer below for helper code.
Live demo: https://onlinegdb.com/S167RI20U
What you're asking for is to decide a type (which must be done at compile time) with information only available at runtime. It is impossible.
C++20 std::span encapsulates ugly syntax in its own non-explicit constructor, so just pass it.
Before C++20, there's std::begin , std::end, std::size, which are not exactly what you need, but may help.
All this is implementable in old compiler, it does not require any special compiler support.
SOLUTION: Use helper functions defined once, that do the appropriate casting and leave the call-site cleaner... I'm surprised that helpers like these aren't available at least for std::array...
For vectors, I will admit that it's a rare use case where you have a compile-time known size for the vector. but I do have a use case where I know my vector contains at least as many elements as an array, and I want the first N of them to be processed through some algorithm. I can guarantee that that many elements are available, and include asserts to boot, etc...
Live demo: https://onlinegdb.com/S167RI20U
template<size_t N, typename T>
using CArrayPtr = T(*)[N];
template<size_t N, typename T>
auto& cArray(array<T, N>& arr) {
return *(CArrayPtr<N, T>)arr.data();
}
template<size_t N, typename T>
auto& cArray(vector<T>& vec) {
return *(CArrayPtr<N, T>)vec.data();
}

How to compare generic structs in C++?

I want to compare structs in a generic way and I've done something like this (I cannot share the actual source, so ask for more details if necessary):
template<typename Data>
bool structCmp(Data data1, Data data2)
{
void* dataStart1 = (std::uint8_t*)&data1;
void* dataStart2 = (std::uint8_t*)&data2;
return memcmp(dataStart1, dataStart2, sizeof(Data)) == 0;
}
This mostly works as intended, except sometimes it returns false even though the two struct instances have identical members (I've checked with eclipse debugger). After some searching I discovered that memcmp can fail due to the struct used being padded.
Is there a more proper way of comparing memory that's indifferent to padding? I'm not able to modify the structs used (they're part of an API I'm using) and the many different structs used has some differing members and thus cannot be compared individually in a generic way (to my knowledge).
Edit: I'm unfortunately stuck with C++11. Should've mentioned this earlier...
No, memcmp is not suitable to do this. And reflection in C++ is insufficient to do this at this point (there are going to be experimental compilers that support reflection strong enough to do this already, and c++23 might have the features you need).
Without built-in reflection, the easiest way to solve your problem is to do some manual reflection.
Take this:
struct some_struct {
int x;
double d1, d2;
char c;
};
we want to do the minimal amount of work so we can compare two of these.
If we have:
auto as_tie(some_struct const& s){
return std::tie( s.x, s.d1, s.d2, s.c );
}
or
auto as_tie(some_struct const& s)
-> decltype(std::tie( s.x, s.d1, s.d2, s.c ))
{
return std::tie( s.x, s.d1, s.d2, s.c );
}
for c++11, then:
template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
return as_tie(lhs) == as_tie(rhs);
}
does a pretty decent job.
We can extend this process to be recursive with a bit of work; instead of comparing ties, compare each element wrapped in a template, and that template's operator== recursively applies this rule (wrapping the element in as_tie to compare) unless the element already has a working ==, and handles arrays.
This will require a bit of a library (100ish lines of code?) together with writing a bit of manual per-member "reflection" data. If the number of structs you have is limited, it might be easier to write per-struct code manually.
There are probably ways to get
REFLECT( some_struct, x, d1, d2, c )
to generate the as_tie structure using horrible macros. But as_tie is simple enough. In c++11 the repetition is annoying; this is useful:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
in this situation and many others. With RETURNS, writing as_tie is:
auto as_tie(some_struct const& s)
RETURNS( std::tie( s.x, s.d1, s.d2, s.c ) )
removing the repetition.
Here is a stab at making it recursive:
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::tie(t))
template<class...Ts,
typename std::enable_if< (sizeof...(Ts) > 1), bool>::type = true
>
auto refl_tie( Ts const&... ts )
RETURNS(std::make_tuple(refl_tie(ts)...))
template<class T, std::size_t N>
auto refl_tie( T const(&t)[N] ) {
// lots of work in C++11 to support this case, todo.
// in C++17 I could just make a tie of each of the N elements of the array?
// in C++11 I might write a custom struct that supports an array
// reference/pointer of fixed size and implements =, ==, !=, <, etc.
}
struct foo {
int x;
};
struct bar {
foo f1, f2;
};
auto refl_tie( foo const& s )
RETURNS( refl_tie( s.x ) )
auto refl_tie( bar const& s )
RETURNS( refl_tie( s.f1, s.f2 ) )
c++17 refl_tie(array) (fully recursive, even supports arrays-of-arrays):
template<class T, std::size_t N, std::size_t...Is>
auto array_refl( T const(&t)[N], std::index_sequence<Is...> )
RETURNS( std::array<decltype( refl_tie(t[0]) ), N>{ refl_tie( t[Is] )... } )
template<class T, std::size_t N>
auto refl_tie( T(&t)[N] )
RETURNS( array_refl( t, std::make_index_sequence<N>{} ) )
Live example.
Here I use a std::array of refl_tie. This is much faster than my previous tuple of refl_tie at compile time.
Also
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::cref(t))
using std::cref here instead of std::tie could save on compile-time overhead, as cref is a much simpler class than tuple.
Finally, you should add
template<class T, std::size_t N, class...Ts>
auto refl_tie( T(&t)[N], Ts&&... ) = delete;
which will prevent array members from decaying to pointers and falling back on pointer-equality (which you probably don't want from arrays).
Without this, if you pass an array to a non-reflected struct in, it falls back on pointer-to-non-reflected struct refl_tie, which works and returns nonsense.
With this, you end up with a compile-time error.
Support for recursion through library types is tricky. You could std::tie them:
template<class T, class A>
auto refl_tie( std::vector<T, A> const& v )
RETURNS( std::tie(v) )
but that doesn't support recursion through it.
You are right that padding gets in your way of comparing arbitrary types in this way.
There are measures you can take:
If you are in control of Data then eg gcc has __attribute__((packed)). It has impact on performance, but it might be worth to give it a try. Though, I have to admit that I dont know if packed enables you to disallow padding completely. Gcc doc says:
This attribute, attached to struct or union type definition, specifies that each member of the structure or union is placed to minimize the memory required. When attached to an enum definition, it indicates that the smallest integral type should be used.
If you are not in control of Data then at least std::has_unique_object_representations<T> can tell you if your comparison will yield correct results:
If T is TriviallyCopyable and if any two objects of type T with the same value have the same object representation, provides the member constant value equal true. For any other type, value is false.
and further:
This trait was introduced to make it possible to determine whether a type can be correctly hashed by hashing its object representation as a byte array.
PS: I only addressed padding, but dont forget that types that can compare equal for instances with different representation in memory are by no means rare (eg std::string, std::vector and many others).
In short: Not possible in a generic way.
The problem with memcmp is that the padding may contain arbitrary data and hence the memcmp may fail. If there were a way to find out where the padding is, you could zero-out those bits and then compare the data representations, that would check for equality if the members are trivially comparable (which is not the case i.e. for std::string since two strings can contain different pointers, but the pointed two char-arrays are equal). But I know of no way to get at the padding of structs. You can try to tell your compiler to pack the structs, but this will make accesses slower and is not really guranteed to work.
The cleanest way to implement this is to compare all members. Of course this is not really possible in a generic way (until we get compile time reflections and meta classes in C++23 or later). From C++20 onward, one could generate a default operator<=> but I think this would also only be possible as a member function so, again this is not really applicable. If you are lucky and all structs you want to compare have an operator== defined, you can of course just use that. But that is not guaranteed.
EDIT: Ok, there is actually a totally hacky and somewhat generic way for aggregates. (I only wrote the conversion to tuples, those have a default comparison operator). godbolt
C++ 20 supports default comaparisons
#include <iostream>
#include <compare>
struct XYZ
{
int x;
char y;
long z;
auto operator<=>(const XYZ&) const = default;
};
int main()
{
XYZ obj1 = {4,5,6};
XYZ obj2 = {4,5,6};
if (obj1 == obj2)
{
std::cout << "objects are identical\n";
}
else
{
std::cout << "objects are not identical\n";
}
return 0;
}
Assuming POD data, default assignment operator copies only member bytes. (actually not 100% sure about that, don't take my word for it)
You can use this to your advantage:
template<typename Data>
bool structCmp(Data data1, Data data2) // Data is POD
{
Data tmp;
memcpy(&tmp, &data1, sizeof(Data)); // copy data1 including padding
tmp = data2; // copy data2 only members
return memcmp(&tmp, &data1, sizeof(Data)) == 0;
}
I believe you may be able to base a solution on Antony Polukhin's wonderfully devious voodoo in the magic_get library - for structs, not for complex classes.
With that library, we are able to iterate the different fields of a struct, with their appropriate type, in purely-general-templated code. Antony has used this, for example, to be able to stream arbitrary structs to an output stream with the correct types, completely generically. It stands to reason that comparison might also be a possible application of this approach.
... but you would need C++14. At least it's better than the C++17 and later suggestions in other answers :-P

Disallow templates that are explicitly specified

I want to have a wide template that 'does whatever it needs to' except for when I have explicitly specified the case.
Specifically, I am overloading operator() to use it for a matrix index of a multidimensional matrix. I also want to allow specifying an arbitrary number of indices using an iterator. Ideally I'd have the following signatures:
operator()(size_t);
operator()(size_t,size_t);
operator()(size_t,size_t,size_t);
...
template<class Iterator> operator()(Iterator,Iterator);
The problem is that operator()(size_t,size_t) is never reached, because the compiler is also able to template template<class Iterator> operator()(Iterator,Iterator). How can I avoid this?
An obvious solution is to use std::vector<size_t>::iterator instead of Iterator. I've tried this, but this narrows the usage elsewhere.
A minimal example:
#include <iostream>
class Foo
{
private:
double data[9];
public:
Foo(){};
double& operator()(size_t i, size_t j)
{
std::cout << "operator()(size_t i, size_t j)" << std::endl;
return data[0];
}
template<class Iterator>
double& operator()(Iterator first, Iterator last)
{
std::cout << "operator()(Iterator first, Iterator last)" << std::endl;
return data[0];
}
};
int main()
{
Foo bar;
bar(0,1);
}
Outputs:
operator()(Iterator first, Iterator last)
whereas I want this case to output
operator()(size_t i, size_t j)
It's almost a certainty that the reason your template gets selected by overload resolution is because the two parameters you're passing in are not really size_t. They're probably ints, or something else. If they were truly size_ts, then I would expect your non-template overload to be picked. Cleaning that up should make things work, as is, but it's simple enough to make this work in any case.
The usual approach in this kind of a situation is to use SFINAE to exclude the template from participating in overload resolution when the passed-in parameter is size_t. Something along the lines of (using C++17):
template<class Iterator,
typename=std::enable_if_t<
std::negation_v<std::is_integral_v<Iterator>>>> operator()(Iterator,Iterator)
{
// ...
}
This is your starting point. It's tempting to use std::is_same_v<Iterator,size_t>, but you'll quickly discover that this only works if you're passing in exactly a size_t. It's very easy for an int to slip in there, if you're not careful, and this is going to fall apart in this case. So you'll probably need to use std::is_integral_v. Hopefully you're not passing in floating point values anywhere, and rely on them being truncated to the next nearest integer value. If you do, you'll have to tweak this further.
The std::is_integral_v and std::enable_if_t shortcuts are available only in C++17 (as well as std::void_t), but it's simple enough to reinvent that wheel in earlier standards, if necessary.
You can also try using SFINAE in the opposite direction: have this template participate in overload resolution only if Iterator resolved to something that std::iterator_traits recognizes. The best approach depends on your specific class's requirements.

std::vector::size return an int type or unsigned int

In most of the programs I write using std::vector, most of my pains are converting
int offset=(int)v.size();
unsigned int offset=(unsigned int)v.size();
It is sad that such problems are reflected in many other questions such as this.
Is there any way to rewire std::vector and force it to give size as an int or unsigned int like?
int offset=v.size_i();
Type-casts make the codes messier that what they are. Although, some programmers enjoy them and feel there is no problem with casting every time.
c++14 solutions are more preferred but c++17 solutions are also welcome.
If some one suggest to change the type of the variable, soon or late another type casting must happen. So it does not solve the problem.
Please consider such ugly phrases
function((int)myvar1.vec[32].size(),(int)myvar2.vec[32].size());
where function only accepts ints. And I have no control over its definition.
you can inherit from std::vector and re-implement size() function to return signed value:
template<typename T, typename Alloc = std::allocator<T> >
class my_vector : public std::vector<T, Alloc>
{
using base_t = std::vector<T,Alloc>;
public:
using base_t::vector;
using base_t::operator =;
int size() const noexcept { return base_t::size(); }
};
std::vector<>.size() is going to be unsigned. It is the way the class is wired, it even includes a typedef for what that type i.e. std::vector<>::size_type. It would be much better for you to get in the habit of using unsigned offsets.
In c++20 you can use std::ssize which returns a signed int.
Use it as:
std::ssize(my_std_vector)
or:
my_std_vector.ssize()
The proposal introducing it to the standard library was P1227R1.

What type should I use for iterator difference to eliminate "possible loss of data" warnings?

I need a common rule for warnings in x64 mode. Which way is better?
Consider the following lines of some code
const int N = std::max_element(cont.begin(), cont.end()) - cont.begin();
or
const int ARR_SIZE = 1024;
char arr[ARR_SIZE];
//...
const int N = std::max_element(arr, arr + ARR_SIZE) - arr;
It is my usual code. I have no problems with x86.
But if I run compiler in x64 mode I have some warnings:
conversion from 'std::_Array_iterator<_Ty,_Size>::difference_type' to 'int', possible loss of data
conversion from '__int64' to 'int', possible loss of data
I want to solve these problems by common rule. Which way is better?
Making static_cast:
const int N = static_cast<int>(
std::max_element(cont.begin(), cont.end()) - cont.begin() );
I think this is not general-purpose. And too much letters.
Replace output type with ptrdiff_t:
const ptrdiff_t N = std::max_element(cont.begin(), cont.end()) - cont.begin();
What should I do then with this unknown type ptrdiff_t?
I'll get another dozen warnings then.
I want to make many operations with N: save, addition, multiplication, cycles and etc.
Important: but what if std::_Array_iterator<_Ty,_Size>::difference_type and ptrdiff_t are different types?
Replace output type with std::_Array_iterator<_Ty,_Size>::difference_type:
//h-file
struct S {
type mymember; // What is the type?
};
//cpp-file
typedef std::vector<int> cont_t;
const cont_t::difference_type N = std::max_element(cont.begin(), cont.end()) - cont.begin();
// Save N
S mystruct;
mystruct.mymember = N; // What type of mystruct.mymember?
How should I save N? What type of mystruct.mymember? I don't know it in h-file.
Your solution.
"what if std::_Array_iterator<_Ty,_Size>::difference_type and ptrdiff_t are different types?" Don't use such a compiler. Also, chances are that it can't formally be different. E.g. this is the case for a vector using the default standard allocator, since that's where it fetches its typedefs, but since the formal guarantee doesn't matter (he he, it really doesn't) I'm not going to look this up in the C++0x draft.
So, use ptrdiff_t.
But it can be a good idea to add a few typedefs, like
typedef ptrdiff_t Size;
typedef ptrdiff_t Index;
and then in your concrete case you'd use Index.
These typedefs are naturally accompanied by custom freestanding countOf, startOf and endOf functions, enabling you to treat raw arrays and standard library containers in exactly the same way.
When you see the name Index it's a bit more clear that it's an index, which can't very naturally get out of the Index or Size set of types almost no matter what you do. E.g., add something to it, it's still an Index. So mostly there will not be a "another dozen warnings".
But in some rare case you'll need to get from Index to just int, say. In and in those rare cases just do a static_cast to shut up the compiler and make your intent clear. Or even a custom static_cast-like narrowTo operation, for expressiveness...
Cheers & hth.,
To keep result of max_element() - cont.begin() you should use
struct Foo { std::vector<int>::difference_type n; };
or
template<typename T> struct Foo { std::vector<T>::difference_type n; };
or
template<T> struct Foo { T n; };
Because difference_type is difference_type, and when you cast it to int you get undefined behavior.
You can use &*c.begin() to convert iterator to pointer, and use ptrdiff_t for difference of this pointers.
I'd use std::ptrdiff_t.
I can't think of a reasonable implementation where std::vector<T>::iterator::difference_type would not be assignable to a std::ptrdiff_t. They're almost certainly going to be the same. If they are not the same, the difference_type would have to be smaller than ptrdiff_t.
Also, ptrdiff_t is a signed type, so if all your code is designed to work with ints, you'll be better off than if you tried to use an unsigned type, like std::vector<int>::size_type.
In visual-studio-2010 you can write:
const auto N = std::max_element( cont.begin(), cont.end() ) - cont.begin();
Use std::vector<int>::size_type:
It is guaranteed to represent any non-negative value of difference_type
It's what all of vector's indexing operations accept
If cont is non-empty, std::max_element(cont.begin(), cont.end()) - cont.begin(); will not evaluate to a negative value. If it is empty, then you shouldn't be doing any of this processing anyhow.
What should I do then with this 'unknown' type? I'll get another dozen warnings then. I want to make many operations with N: save, addition, multiplication, cycles and etc.
You won't get any warnings if you use the type consistently and limit the usage to where you actually need it. N is an index into a vector; that's all it's good for. Any meaningful operation you perform on it is going to result in another possible index into a vector.
My solution is to use a type that is known to be large enough, based on the domain knowledge that I have but which may not be available to the compiler.
If the compiler then complains about a possible loss of data, I add a cast (which is guaranteed safe, because I know beforehand that the target type must be large enough).