I'm writing a library and wonder what's the best practice for datatypes used in a public API.
Given the function
void foo (int bar)
which expects an index to some internal array/container. What type should that be? Because an index can never be negative I could use unsigned int or size_t. Or should I stick with a plain int and assert / throw if some invalid value is provided?
In general: Should I choose a type based on the valid data range (e.g. to avoid negative checks) or not?
EDIT: another example, suppose my library provides a function for printing a file. The user can choose the range of pages to be printed:
void print (int page_from, int page_to)
If the array/container you are talking about is just a generic abstract application-independent array, then the most appropriate type would be size_t. You can, of course, provide a typedef name for the type in your interface. Again, this is only appropriate when you are working with abstract arrays, like in a generic container library, or a generic sort function etc.
One you get into an application specific area, size_t is no longer the appropriate type. In your application specific area that index would normally have some application-specific semantics not immediately related to arrays. For example, it can be an "employee id" of some sort, or "cell number" or "color index" or something else. In such cases you would normally already have a pre-chosen integer type to represent the corresponding quantity. (And the choice will not normally have anything to do with arrays.) This is exactly the type you should use in your interface.
As for signedness/unsignedness of the type... I for one firmly believe that unsigned quantities should be represented by unsigned types, i.e. a normal array index should be unsigned.
The best advice here would probably be to go with the existing practice (i.e. what C++ standard libraries do). Broadly speaking, this means at least using an unsigned type here; if you're actually using that type directly as an array/pointer index (and your abstraction is transparent in that regard), then size_t might be called for.
If foo is a member function of some container-like class, then you may also consider typedefing something like size_type on it, and using that.
I vote for using unsigned. Even better, use stdint.h and use something like uint32_t.
Related
Let me consider that I have 4 bytes that describe some real system parameters. Suppose that could be interpreted as float, uint32_t and boolean. The main idea to store and process this variables together. Now I use one class that (very simplified) have array of 4 bytes, functions float toFloat(), uint32_t toInt(), bool toBool() and parameter ID (which specifies storing value type). So I need one function T getValue() which will be returning the value of correct type T. So my question is: what is the most correct way to do so? Should I use templates, inheritance, its combination or something else?
You could use a std::variant:
std::variant<float, uint32_t, bool> bytes(3.1415);
This seems like a perfect usecase for unions. The only thing amiss is that in a union you don't know which value type was stored. You could either attach the type information, for example allowing access to the union member with an accessor setting the type up, or if you have any other mean to know the type you could use that.
Arrays must have unique datatypes, otherwise you must build a parallel array structure using multiple arrays in conjunction.
I wonder if there is a reason why the std::sto series (e.g. std::stoi, std::stol) is not a function template, like that:
template<typename T>
T sto(std::string const & str, std::size_t *pos = 0, int base = 10);
and then:
template<>
int sto<int>(std::string const & str, std::size_t *pos, int base)
{
// do the stuff.
}
template<>
long sto<long>(std::string const & str, std::size_t *pos, int base)
{
// do the stuff.
}
/* etc. */
In my sense, that would be a better design, because for the moment, when I have to convert a string in whatever numerical value an user want, I have to manually manage each case.
Is there a reason to not have such a template function? Is there an assumed choice, or is this just done like that?
Looking at the description of these functions at cppref, I note the following:
... Interprets a signed integer value in the string str.
1) calls std::strtol(str.c_str(), &ptr, base)...
and strol a "C" standard function that's also available in C++.
Reading further, we see: (for the c++ sto* functions):
Return value
The string converted to the specified signed integer type.
Exceptions
std::invalid_argument if no conversion could be performed
std::out_of_range if the converted value would fall out of the range of the result type or if the underlying function (std::strtol or
std::strtoll) sets errno to ERANGE.
So while I have no original source for this, and indeed have never worked with these functions, I would guess that:
TL;DR : These functions are C++-ish wrappers around already existing C/C++ functions -- strtol* -- so they resemble these functions as close as possible.
I have to manage manually each case. Is there a reason to not have such a template function?
In case of such questions, Eric Lippert (C#) usually says something along the lines:
If a feature is missing, then it's missing because noone implemented it yet. And that's because either noone else earlier wanted yet, or because it was considered not worth the effort, or because it couldn't have been finished before publishing the current release".
Here, I guess it's the "not worth" part, but I have neither asked the commitee about, nor managed to find any answer in old questions and faqs. I didn't spend much time searching though.
I say this because I suppose that most common of these functions' functionality (if not all of) is already contained in stream classes, like istringstream. Just like cin/etc, this one also has an all-having operator >>, overloaded for all base numeric types (and more).
Furthermore, the stream manipulators like std::hex (std::setbase) already solve the problem of passing various type-dependent configuration parameters to the actual conversion functions. No problems with mixed function signatures (like those mentioned by DavidHaim in his answer). Here's just a single operator>>.
So.. since if we have it in streams, if we already can read numbers/etc from strings with simple foo >> bar >> setbase(42) >> baz >> ..., then I think it was not worth the effort to add more complicated layers to old C runtime functions.
No proof for that though. Just a hunch.
The problem with template specialization is that the specialization requires you to match the original template function signature, so each specialization must implement the interface of (string,pos,base).
If you would like to have some other type which does not follows this interface, you are in trouble.
Suppose that, in the future, we would like to have sto<std::pair<int,int>>. We will want to have pos and base for the first and the second stringified integer. we would like the signature to be in the form of string,pos1,base1,pos2,base2. Since sto signature is already set, we cannot do it.
You can always wrap std::sto* in your implementation of sto for integral types, but you cannot do that the other way around.
The purpose of these functions is to provide simple conversions for common cases. They are not intended as a general-purpose conversion suite. std::ostringstream is much better for that kind of thing.
In my sense, there would be a better design, because for the moment,
when I have to convert a string in whatever numerical value an user
want, I have to manage manually each case.
No, it would not. Templates goal (deliberately setting T-MP apart) is not to replace overloading; you should always prefer overloading to templates. Actually, it's something the language already does for you! Between a candidate function and a possible template instantation, the former will be prefered. Using language features for the sake of it is bad.
I don't see how templates could help either. Whatever type the user decides to input, it won't be known till runtime, and template types are deduced at compile time. C++ is a statically typed language. In this case, templates will just add an unneeded layer of complexity over normal function overloading.
I recently read up how classes are allowed to define their own local names for types. One of the famous examples being size_type, provided almost by all STL containers. It was also mentioned that doing so helps hide implementation details from the user of the class. I am not quite sure how this is the case.
What are some examples where defining local names for types might be useful and how doing so hides implementation details?
Please provide some examples where defining local names for types might be useful and how it hides implementation details.
its more usefull when you use templated algorithms or containers, which might assume that your type has such type alias. So even if you modify type for size_type - i.e. change for some reason from size_t to int, then your type will still work with those algorithms / containers.
Otherwise, presence of size_type are required by standard when you for example implement your own allocator.
Suppose you have a program where you define several variables of type size_type and that it is defined somewhere as an int.
Then, upon analysis and reflection, you realize that the variables never assume values igger than 10 thousand. Therefore, the 32 bits used to allocate each of these variables are somewhate an overkill. In this case, you can redefine size_type as being of short type, instead of int. Therefore you will end up saving some memory.
Regarding the examples, you can check clock_t, char16_t, char32_t, wchar_t, true_type and false_type.
so i use BOOST.EXTENTION to load modules. I have a special file that describes each module. I read variables from that file.
so such example:
shared_library m("my_module_name");
// Call a function that returns an int and takes a float parameter.
int result = m.get<int, float>("function_name")(5.0f);
m.close();
for me would turn into:
shared_library m("my_module_name");
// Call a function that returns an int and takes a float parameter.
int result = m.get<myMap["TYPE_1_IN_STRING_FORM"], myMap["TYPE_2_IN_STRING_FORM"]>("function_name")(5.0f);
m.close();
How to create such map that would map standard and costume types?
Update:
may be with variant:
shared_library m("my_module_name");
int result = m.get<boost::variant< int, float, ... other types we want to support >, boost::variant< int, float, ... other types we want to support > >("function_name")(5.0f);
m.close();
can halp? so we would not care as long as all types we want are declared in it?
For that, you would need a heterogeneous map - that is, its elements can be of different types. Furthermore you would need the ability to return types from functions, not just variables.
Now, a heterogeneous map would be possible with Boost.Variant or a simple union, but that binds it to compile time: we need to know every type that is possible to create that variant/union.
Of course a Boost.Any would be possible to store everything and its dog, but the problem strikes again: you need to extract the real type out of that Boost.Any again. The problem repeats itself. And if you know the real type, you can aswell just make a variant/union and save yourself the any_cast trouble.
Now, for another troublesome thing:
m.get<myMap["TYPE_1_IN_STRING_FORM"], myMap["TYPE_2_IN_STRING_FORM"]>
To make the above line work, you'd need two features that C++ doesn't have: the ability to return types and runtime templates. Lets ignore the first point for a moment.
Templates are compile-time, and the get function is such a template. Now, to use that template, your myMap would need to be able to return types at compile-time, while getting populated at runtime. See the contradiction? That's why runtime templates would be needed.
Sadly, exactly those three things are not possible (or extremely hard and very very limited) in C++ at runtime: heterogeneous data types (without constant size), returning types and templates.
Everything that involves types needs to be done at compile-time. This blogpost by #Gman somewhat correlates with that problem. It's definitly worth a read if you want to know what C++ just can't do.
So, to conclude: You'll need to rethink and refactor your problem and solution. :|
I'm in the process of creating a class that stores metadata about a particular data source. The metadata is structured in a tree, very similar to how XML is structured. The metadata values can be integer, decimal, or string values.
I'm curious if there is a good way in C++ to store variant data for a situation like this. I'd like for the variant to use standard libraries, so I'm avoiding the COM, Ole, and SQL VARIANT types that are available.
My current solution looks something like this:
enum MetaValueType
{
MetaChar,
MetaString,
MetaShort,
MetaInt,
MetaFloat,
MetaDouble
};
union MetaUnion
{
char cValue;
short sValue;
int iValue;
float fValue;
double dValue;
};
class MetaValue
{
...
private:
MetaValueType ValueType;
std::string StringValue;
MetaUnion VariantValue;
};
The MetaValue class has various Get functions for obtaining the currently stored variant value, but it ends up making every query for a value a big block of if/else if statements to figure out which value I'm looking for.
I've also explored storing the value as only a string, and performing conversions to get different variant types out, but as far as I've seen this leads to a bunch of internal string parsing and error handling which isn't pretty, opens up a big old can of precision and data loss issues with floating point values, and still doesn't eliminate the query if/else if issue stated above.
Has anybody implemented or seen something that's cleaner to use for a C++ variant data type using standard libraries?
As of C++17, there’s std::variant.
If you can’t use that yet, you might want Boost.Variant. A similar, but distinct, type for modelling polymorphism is provided by std::any (and, pre-C++17, Boost.Any).
Just as an additional pointer, you can look for “type erasure”.
While Konrad's answer (using an existing standardized solution) is certainly preferable to writing your own bug-prone version, the boost variant has some overheads, especially in copy construction and memory.
A common customized approach is the following modified Factory Pattern:
Create a Base interface for a generic object that also encapsulates the object type (either as an enum), or using 'typeid' (preferable).
Now implement the interface using a template Derived class.
Create a factory class with a templateized create function with signature:
template <typename _T> Base * Factory::create ();
This internally creates a Derived<_T> object on the heap, and retuns a dynamic cast pointer. Specialize this for each class you want implemented.
Finally, define a Variant wrapper that contains this Base * pointer and defines template get and set functions. Utility functions like getType(), isEmpty(), assignment and equality operators, etc can be appropriately implemented here.
Depending on the utility functions and the factory implementation, supported classes will need to support some basic functions like assignment or copy construction.
You can also go down to a more C-ish solution, which would have a void* the size of a double on your system, plus an enum for which type you're using. It's reasonably clean, but definitely a solution for someone who feels wholly comfortable with the raw bytes of the system.
C++17 now has std::variant which is exactly what you're looking for.
std::variant
The class template std::variant represents a type-safe union. An
instance of std::variant at any given time either holds a value of one
of its alternative types, or in the case of error - no value (this
state is hard to achieve, see valueless_by_exception).
As with unions, if a variant holds a value of some object type T, the
object representation of T is allocated directly within the object
representation of the variant itself. Variant is not allowed to
allocate additional (dynamic) memory.
Although the question had been answered for a long time, for the record I would like to mention that QVariant in the Qt libraries also does this.
Because C++ forbids unions from including types that have non-default
constructors or destructors, most interesting Qt classes cannot be
used in unions. Without QVariant, this would be a problem for
QObject::property() and for database work, etc.
A QVariant object holds a single value of a single type() at a time.
(Some type()s are multi-valued, for example a string list.) You can
find out what type, T, the variant holds, convert it to a different
type using convert(), get its value using one of the toT() functions
(e.g., toSize()) and check whether the type can be converted to a
particular type using canConvert().