Is this possible in zig? And if so how would something like the following C++ code look in Zig?
template<class T>
class vec3
{
union
{
struct{ T x,y,z; };
T vec_array[3];
};
};
No, there is no such thing supported in Zig, and it is unlikely there ever will be. The closest you'll get is something like this:
const std = #import("std");
pub fn Vec3(comptime T: type) type {
return extern union {
xyz: extern struct { x: T, y: T, z: T },
arr: [3]T,
};
}
test {
var v3: Vec3(u32) = .{ .arr = .{ 42, 73, 95 } };
try std.testing.expectEqual(v3.arr[0], v3.xyz.x);
try std.testing.expectEqual(v3.arr[1], v3.xyz.y);
try std.testing.expectEqual(v3.arr[2], v3.xyz.z);
}
where the extern qualifiers here make the containers behave in accordance with the C ABI (and in the case of the union, makes it defined behavior to access any member).
See this comment under proposal #985 for a fairly comprehensive rationale on as to why "anonymous field nesting" was rejected.
Related
How can this const print variable behave like a function?
const print = #import("std").debug.print;
print("hello, world", .{});
I understand you can assign expressions to variables. But this seems to behave like a precompiler macro in c/c++, I wouldn't have guessed that.
Is it because "all variables declared in a comptime expression are implicitly comptime variables" and # makes it a comptime expression, so it is evaluated before compilation, much like a macro would in c?
Could someone elaborate a bit? This seems a very powerful feature.
# does not indicate a comptime expression; rather # prefixes built-in functions in Zig. #import returns a struct that provides access to the declarations made public by the imported file.
The expression #import("std").debug.print evaluates to the print function defined in the standard library file std/debug.zig; it is not the expression that is assigned to print in the posted code, but the function. That is, the posted code works because print in OP code is actually a function. This can be seen by running the code below:
const print = #import("std").debug.print;
pub fn main() void {
print("#TypeOf print: {}\n", .{ #TypeOf(print) });
}
Results:
$ zig run print_type.zig
#TypeOf print: fn(comptime []const u8, anytype) void
Function Assignment
OP has asked for another example of assigning a function that is not imported to an identifier:
const print = #import("std").debug.print;
fn my_function(msg: []const u8) void {
print("{s}\n", .{ msg });
}
const my_function_alias = my_function;
pub fn main() void {
const another_function_alias = my_function;
const yet_another_function_alias = my_function_alias;
my_function("mf");
my_function_alias("mfa");
another_function_alias("afa");
yet_another_function_alias("yafa");
}
Program output:
$ zig run function_assignment.zig
mf
mfa
afa
yafa
I'm new to Zig and wanted to use the cImport to call out to the GNU Multiprecision library GMP. I got this to work but it feels awkward because Zig apparently doesn't cast from arrays to pointers by default and GMP uses this approach to pass by reference. Is there a cleaner approach than mine? Are there existing examples of Zig calling GMP?
const gmp = #cImport({
#cInclude("gmp.h");
});
pub fn main() void {
var x: gmp.mpz_t = undefined;
gmp.mpz_init(&x[0]);
gmp.mpz_set_ui(&x[0], 7);
gmp.mpz_mul(&x[0], &x[0], &x[0]);
_ = gmp.gmp_printf("%Zd\n", x);
}
You should be able to drop the [0]:
const gmp = #cImport({
#cInclude("gmp.h");
});
pub fn main() void {
var x: gmp.mpz_t = undefined;
gmp.mpz_init(&x);
gmp.mpz_set_ui(&x, 7);
gmp.mpz_mul(&x, &x, &x);
_ = gmp.gmp_printf("%Zd\n", x);
}
This is a much simplified version of my real issue but hopefully demonstrates my question in a concise manner.
My question is about the interface to printKeys. I have to pass in the type of the data to be printed as a comptime parameter, and the easiest way to get this is to use #TypeOf on the map at the point of calling it.
Coming from C++ this seems slightly inelegant that the type can't be inferred, although I do like being explicit too.
Is there a more idiomatic way to have a generic function in zig that doesn't need this use of #TypeOf at the point of calling, or a better way to do this in general?
const std = #import("std");
fn printKeys(comptime MapType: type, data: MapType) void {
var iter = data.keyIterator();
while (iter.next()) | value | {
std.debug.print("Value is {}\n", .{value.*});
}
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var map = std.AutoHashMap(i32, []const u8).init(allocator);
defer map.deinit();
try map.put(10, "ten");
try map.put(12, "twelve");
try map.put(5, "five");
printKeys(#TypeOf(map), map);
}
use anytype. you can find more examples in zig docs (Ctrl + F) and search anytype
fn printKeys(data: anytype) void {
...
}
pub fn main() !void {
...
printKeys(map);
}
I was reading this Q/A here and as my question is similar but different I would like to know how to do the following:
Let's say I have a basic non template non inherited class called Storage.
class Storage {};
I would like for this class to have a single container (unordered multimap) is where I'm leaning towards... That will hold a std::string for a name id to a variable type T. The class itself will not be template. However a member function to add in elements would be. A member function to add might look like this:
template<T>
void addElement( const std::string& name, T& t );
This function will then populate the unorderd multimap. However each time this function is called each type could be different. So my map would look something like:
"Hotdogs", 8 // here 8 is int
"Price", 4.85f // here 4.8f is float.
How would I declare such an unorderd multimap using templates, variadic parameters, maybe even tuple, any or variant... without the class itself being a template? I prefer not to use boost or other libraries other than the standard.
I tried something like this:
class Storage {
private:
template<class T>
typedef std::unorderd_multimap<std::string, T> DataTypes;
template<class... T>
typedef std::unordered_multimap<std::vector<std::string>, std::tuple<T...>> DataTypes;
};
But I can not seem to get the typedefs correct so that I can declare them like this:
{
DataTypes mDataTypes;
}
You tagged C++17, so you could use std::any (or std::variant if the T type can be a limited and know set of types`).
To store the values is simple.
#include <any>
#include <unordered_map>
class Storage
{
private:
using DataTypes = std::unordered_multimap<std::string, std::any>;
DataTypes mDataTypes;
public:
template <typename T>
void addElement (std::string const & name, T && t)
{ mDataTypes.emplace(name, std::forward<T>(t)); }
};
int main()
{
Storage s;
s.addElement("Hotdogs", 8);
s.addElement("Price", 4.85f);
// but how extract the values ?
}
But the problem is that now you have a element with "Hotdogs" and "Price" keys in the map, but you have no info about the type of the value.
So you have to save, in some way, a info about the type of th value (transform the value in a std::pair with some id-type and the std::any?) to extract it when you need it.
I've done something along those lines, the actual solution is very specific to your problem.
That being said, I'm doing this on a vector, but the principle applies to maps, too.
If you're not building an API and hence know all classes that will be involved you could use std::variant something along the lines of this:
#include <variant>
#include <vector>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
int main() {
auto storage = std::vector<storage_t>{};
storage.push_back(ex1{});
storage.push_back(ex2{});
auto op = unspecific_operation{};
for(const auto& content : storage) {
std::visit(op, content);
}
return 0;
}
which will output:
got ex1
got ex2
If I remember correctly, using std::any will enable RTTI, which can get quite expensive; might be wrong tho.
If you provide more specifics about what you actually want to do with it, I can give you a more specific solution.
for an example with the unordered map:
#include <variant>
#include <unordered_map>
#include <string>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
class Storage {
private:
using map_t = std::unordered_multimap<std::string, storage_t>;
map_t data;
public:
Storage() : data{map_t{}}
{}
void addElement(std::string name, storage_t elem) {
data.insert(std::make_pair(name, elem));
}
void doSomething() {
auto op = unspecific_operation{};
for(const auto& content : data) {
std::visit(op, content.second);
}
}
};
int main() {
auto storage = Storage{};
storage.addElement("elem1", ex1{});
storage.addElement("elem2", ex2{});
storage.addElement("elem3", ex1{});
storage.doSomething();
return 0;
}
I'm confused by the OpenCV Mat element types. This is from the docs:
There is a limited fixed set of primitive data types the library can operate on.
That is, array elements should have one of the following types:
8-bit unsigned integer (uchar)
8-bit signed integer (schar)
16-bit unsigned integer (ushort)
16-bit signed integer (short)
32-bit signed integer (int)
32-bit floating-point number (float)
64-bit floating-point number (double)
...
For these basic types, the following enumeration is applied:
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
It's known that C++ standard doesn't define the size of basic types in bytes, so how do they use such assumptions? And what type should I expect from, let's say, CV_32S, is it int32_t or int?
Developing from Miki's answer,
In OpenCV 3 definition has moved to modules/core/include/opencv2/core/traits.hpp, where you can find:
/** #brief A helper class for cv::DataType
The class is specialized for each fundamental numerical data type supported by OpenCV. It provides
DataDepth<T>::value constant.
*/
template<typename _Tp> class DataDepth
{
public:
enum
{
value = DataType<_Tp>::depth,
fmt = DataType<_Tp>::fmt
};
};
template<int _depth> class TypeDepth
{
enum { depth = CV_USRTYPE1 };
typedef void value_type;
};
template<> class TypeDepth<CV_8U>
{
enum { depth = CV_8U };
typedef uchar value_type;
};
template<> class TypeDepth<CV_8S>
{
enum { depth = CV_8S };
typedef schar value_type;
};
template<> class TypeDepth<CV_16U>
{
enum { depth = CV_16U };
typedef ushort value_type;
};
template<> class TypeDepth<CV_16S>
{
enum { depth = CV_16S };
typedef short value_type;
};
template<> class TypeDepth<CV_32S>
{
enum { depth = CV_32S };
typedef int value_type;
};
template<> class TypeDepth<CV_32F>
{
enum { depth = CV_32F };
typedef float value_type;
};
template<> class TypeDepth<CV_64F>
{
enum { depth = CV_64F };
typedef double value_type;
};
In most of the cases/compilers you should be fine using C++ exact data types. You wouldn't have problems with single byte data types (CV_8U -> uint8_t and CV_8U -> int8_t) as unambiguously defined in C++. The same for float (32bit) and double (64bit). However, it is true that for other data types to be completely sure you use the correct data type (for example when using the at<> method) you should use for example:
typedef TypeDepth<CV_WHATEVER_YOU_USED_TO_CREATE_YOUR_MAT>::value_type access_type;
myMat.at<access_type>(y,x) = 0;
As a side note, I am surprised they decided to take such an ambiguous approach, instead of simply using exact data types.
Therefore, regarding your last question:
What type should I expect from, let's say, CV_32S?
I believe the most precise answer, in OpenCV 3, is:
TypeDepth<CV_32S>::value_type
In core.hpp you can find the following:
/*!
A helper class for cv::DataType
The class is specialized for each fundamental numerical data type supported by OpenCV.
It provides DataDepth<T>::value constant.
*/
template<typename _Tp> class DataDepth {};
template<> class DataDepth<bool> { public: enum { value = CV_8U, fmt=(int)'u' }; };
template<> class DataDepth<uchar> { public: enum { value = CV_8U, fmt=(int)'u' }; };
template<> class DataDepth<schar> { public: enum { value = CV_8S, fmt=(int)'c' }; };
template<> class DataDepth<char> { public: enum { value = CV_8S, fmt=(int)'c' }; };
template<> class DataDepth<ushort> { public: enum { value = CV_16U, fmt=(int)'w' }; };
template<> class DataDepth<short> { public: enum { value = CV_16S, fmt=(int)'s' }; };
template<> class DataDepth<int> { public: enum { value = CV_32S, fmt=(int)'i' }; };
// this is temporary solution to support 32-bit unsigned integers
template<> class DataDepth<unsigned> { public: enum { value = CV_32S, fmt=(int)'i' }; };
template<> class DataDepth<float> { public: enum { value = CV_32F, fmt=(int)'f' }; };
template<> class DataDepth<double> { public: enum { value = CV_64F, fmt=(int)'d' }; };
template<typename _Tp> class DataDepth<_Tp*> { public: enum { value = CV_USRTYPE1, fmt=(int)'r' }; };
You can see that CV_32S is the value for the type int, not int32_t.
While C++ doesn't define the size of an element, the question is hypothetical: for systems OpenCV is run on, the sizes are known. Given
cv::Mat m(32,32,CV_32SC1, cv:Scalar(0));
std::cout << "size of the element in bytes: " << m.depth() << std::endl;
std::cout << "or " << m.step.p[ m.dims-1 ]/m.channels() << std::endl;
So how can you be sure it is int?
An attempt to call
int pxVal = m.at<int>(0,0);
will
CV_DbgAssert( elemSize()==sizeof(int) );
Where the left hand is defined via the cv::Mat::flags -- in this example as the predefined depth of the CV_32SC1 equal to
CV_DbgAssert( m.depth() == sizeof(int) )
or
CV_DbgAssert( 4 == sizeof(int) )
So if you succeeded you are left only the endianness. And that was checked when the cvconfig.h was generated (by CMake).
TL;DR, expect the types given in the header and you'll be fine.
You can find all definitions on your questions in opencv's sources.
See https://github.com/Itseez/opencv/blob/master/modules/core/include/opencv2/core/cvdef.h file.
I have found several #define in OpenCV's code related to CV_8UC1, CV_32SC1, etc. To make the enumerations work, OpenCV put additional codes to convert the plain numbers together as a parameter (i.e, CV_8UC1, CV_16UC2...are all represented by their respective numbers), and break the depth and channels apart in the definition of CvMat(I guess Mat may have similar codes in its definition). Then, it uses create() to allocate spaces for the matrix. Since create() is inline, I can only guess that it is similar to malloc() or something.
As source codes changes a lot from 2.4.9 to 3.0.0, I need to post more evidence later. Please allow me a little time to find out more and edit my answer.
In short the table you provided is correct.
If you want to directly access a pixel, you typecast it to the specifier to the right, for example CV_32S is a signed 32-bit.
The S always means a signed integral number (signed char, signed short, signed int)
The F always means a floating point number (float, double)
The U always means an unsigned integral number.
The enumeration is used only when creating or converting a Mat. It's a way of telling the mat which is the desired type, as I understand it it's the C predecessor to when templates were not used.
I use the C functionality exclusively, and in order to create an image, it would be an error to pass the following:
cvCreateImage(mySize,char, nChannels);
Instead, I pass the following:
cvCreateImage(mySize, IPL_DEPTH_8U, nChannels);
Here, the IPL_DEPTH_8U is a flag that is used by the function. The function itself has a switch-type statement that checks the flag. The actual value of the flag is most often meaningless as it's most often controlled by conditional, not algebraic statements.