Conversation
Use 'CamelCase' for types / enums. All capitals letters are reserved for macro / constants itself. BTW, This is not regular (simple) enum. This is "bit-set" enum, for example: |
adafff3 to
2e2892d
Compare
|
Some design work is required to resolve "enum" handling. Enum categoriesI see these classes of enums used in OpenCV:
Handling enums in Python.Currently all enums are "int" contants in Python. This approach is not safe and error prone. Unfortunately, only Python 3.6+ have "native" enum types: We should emulate this for other Python versions somehow. Usage compatibility between C++ and PythonIn C++ enum type is not used for accessing of enum value (added to namespace/class): So probably we should duplicate enum values into current module to save compatibility with existed Python code and keep similarity between C++/Python code: |
|
8fd21a8 to
1cf6d48
Compare
|
Thanks for revisiting enums for OpenCV 4 this was bothering me too.
some of those enums in classes are there for encapsulation. However they seem to cause problems for Python wrapper (#10681). Could this be supported for wrapping? Should those enums be moved to be consistent with rest of the OpenCV?
Python enums are basically
I can't see why that should cause any issues for Eigen. What was the exact error? If possible, I think introducing this operator for "flags" enums like this would be quite an easy and backward-compatible way. Of cause wrap this in macro, so we can easily add it for enums that need it. Like |
|
|
||
| //////////////////////////////// Enum operators ////////////////////////////// | ||
|
|
||
| template<typename T, typename std::enable_if< std::is_enum<T>::value >::type* = nullptr> |
There was a problem hiding this comment.
Maybe consider adding this only for "flags" enums on per-enum basis. For "mode" enums this does not make sense. It could confuse users to use this to pass OR-ed values where it should not be used.
There was a problem hiding this comment.
Also operator | () is needed too.
If I define: template<typename T, typename std::enable_if< std::is_enum<T>::value >::type* = nullptr>
static T operator|(const T& a, const T& b)
{
typedef typename std::underlying_type<T>::type EnumType;
return static_cast<T>(static_cast<EnumType>(a) | static_cast<EnumType>(b));
}Then the following errors occurs, and while I can manage the first bullet, I do not know how to fix the second:
|
1cf6d48 to
a69f060
Compare
|
Just don't use templates. Separate operator definition for each "flags" enum, something like this:
I like this idea to declare multiple operators. |
|
that seems to be the same issue. constexpr should fix that. However, I think it is not a good idea to declare templated @alalek exactly! |
a69f060 to
80d8839
Compare
|
To resolve To be specific: (you should add more operators for &, |=, &= etc.) Then declare constexpr allows to use the operator in constant expressions. This approach allows us to declare the operator only for enums where it makes sense. BTW: I'm not sure if we need |
cv3d
left a comment
There was a problem hiding this comment.
How about this solution? I guess it is mature enough, is not it?
| template<typename T, typename T2, typename std::enable_if< std::is_enum<T>::value | ||
| && T::CV_FLAGS_ENUM == T::CV_FLAGS_ENUM >::type* = nullptr> | ||
| static T operator|(const T2& a, const T& b) | ||
| { |
There was a problem hiding this comment.
How about utilizing SFINAE and introducing CV_FLAGS_ENUM in the flag-based enums? I guess this solution is elegant enough.
| enum AccessFlag { ACCESS_READ=1<<24, ACCESS_WRITE=1<<25, | ||
| ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26, | ||
| CV_FLAGS_ENUM = ACCESS_READ }; | ||
|
|
There was a problem hiding this comment.
As you can see, CV_FLAGS_ENUM is introduced to enable bitwise operators, and it can take any value, and in this case, it is assigned ACCESS_READ for safety against ignorant users.
There was a problem hiding this comment.
Cool. I think that would work.
The obvious disadvantage is that we have extra CV_FLAGS_ENUM in every flags enum and in documentation etc. Also in my experience widely used SFINAE can affect compilation times pretty badly.
Therefore, I would prefer the solution above, but this is certainly workable too. If you want to go with this, I suggest to add constexpr to allow using it in constant expressions.
There was a problem hiding this comment.
constexpr is available from Visual Studio 2015.
Do we really want to drop support of Visual Studio 2013? It is still widely used...
| int k = kind(); | ||
| int accessFlags = flags & ACCESS_MASK; | ||
| AccessFlag accessFlags = flags & ACCESS_MASK; | ||
|
|
There was a problem hiding this comment.
@hrnr The problem with the macro-based solution is that it cannot handle two types T1, T2, thus the above expression would not compile since flags is int. Of couse we can introduce cast in such cases, but this might break user code as well. The only solution that seems to work with minimal changes is a template-based one. Accordingly, I would like to go with my proposal, at least for the time-being.
There was a problem hiding this comment.
What is about this?
AccessFlag operator & (const int a, const AccessFlag& b)
There was a problem hiding this comment.
This also would work, but I am not sure if int is the only type utilized with bitwise operations (how about long?), and I do not think we want to provide all the variants. On the other hand, the template-based solution referenced above is just doing that with minimal effort, I guess.
There was a problem hiding this comment.
int, long and other helper operators can be placed under CV_FLAGS_ENUM(enumType) macro:
enum AccessFlag { ... };
CV_FLAGS_ENUM(AccessFlag); // define helper operators here
It can be added for each bit-set/flags enum types.
80d8839 to
25c0bd6
Compare
| CV_FLAGS_ENUM_OR_EQ (EnumType, int); \ | ||
| CV_FLAGS_ENUM_AND_EQ(EnumType, int); \ | ||
| CV_FLAGS_ENUM_XOR_EQ(EnumType, int); \ | ||
|
|
There was a problem hiding this comment.
Although it is hard to maintain, I need to admit that it is looks beautiful and have optimal performance.
There was a problem hiding this comment.
Nice work. Keep going!
I think that int is enough for the overloads as enums convert implicitly to ints (we have only int enums). Moreover, I think we should get rid of those overloads one day to disallow AccessFlags flags = cv::RANSAC | ACCESS_WRITE;. Casts would need to be added to some places though.
There was a problem hiding this comment.
The good news is, if cv::RANSAC is not an int, AccessFlags flags = cv::RANSAC | ACCESS_WRITE would not work.
That is another reason to avoid using int, and use enum types instead.
25c0bd6 to
cff9c46
Compare
| accessFlags &= ~ACCESS_READ; | ||
| if (!(arg.flags & KernelArg::WRITE_ONLY)) | ||
| accessFlags &= ~ACCESS_WRITE; | ||
| bool ptronly = (arg.flags & KernelArg::PTR_ONLY) != 0; |
There was a problem hiding this comment.
@alalek @hrnr We do not have ACCESS_NONE to write something like ((arg.flags & KernelArg::READ_ONLY) ? ACCESS_READ : ACCESS_NONE) | ((arg.flags & KernelArg::WRITE_ONLY) ? ACCESS_WRITE : ACCESS_NONE) and even the ACCESS_MASK is not covering the FAST_ACCESS bit...
In this case, all I can think of is the negative logic. Is there any better idea to do this more efficiently?
There was a problem hiding this comment.
For any "flags" enum, "0" is default "none" value.
I would like to avoid introducing separate meaningless enum value like ACCESS_NONE. Perhaps we can write here (AccessFlag)0 instead.
It is better to drop "negative logic" in code, like your suggestion.
Alternatively we can try to overload operator - () for "flag" enums (but we should make it safe).
e6f1bbc to
20517ce
Compare
|
|
||
| // Exposes the listed 5 members of the enum class AccessFlag to the current namespace | ||
| CV_ENUM_CLASS_EXPOSE(AccessFlag, 5, ACCESS_READ, ACCESS_WRITE, ACCESS_RW, ACCESS_MASK, ACCESS_FAST); | ||
| @endcode |
There was a problem hiding this comment.
Making all enums enum class would be, however, a big disaster (without any backward compatibility stuff).
I managed to get C++11 enum classes working with backwards compatibility and minimal changes.
Basically, instead of:
enum xyz { m1, m2, m3};one would define:
enum class xyz { m1, m2, m3};
CV_ENUM_CLASS_EXPOSE(xyz, m1, m2, m3);and in case it is a flag enum, then CV_ENUM_FLAGS_CLASS(AccessFlag); instead of CV_ENUM_FLAGS(AccessFlag); would do the trick.
Only Python module still have issues with that, but I believe I can work around that as well.
@alalek @hrnr Shall I consider changing the enums into enum classes?
20517ce to
a01d44a
Compare
|
@alalek I need your help, please! I am writing the overloaded legacy API, but I got thousands of More importantly, the overloaded API causes ambiguity such as in this build. @alalek @hrnr @vpisarev |
|
Preserving "legacy" API with "int" in my meaning is: This is already done in interface.h. No need to have both "overloads" with "enum" and "int" in OpenCV binaries. Another "legacy" API compatibility is about using It will be good if we handle the most part of cases from your commit "Refactored code for type-safety". So, save your commit "Refactored code for type-safety" in a separate branch (for further/separate PR) and remove it from the current patch. |
|
Below are my proposals for this snippet (from mat.hpp):
Remove this. Do not touch C-only files. Perhaps this should be done in other way (compiler warning, instead of runtime). Lets remove this and leave for further changes.
Use "inline":
Perhaps we don't want to see here "5" instead of Completely legacy code which wants "int" should re-compile own OpenCV without |
|
@alalek Even with that, there is still the cases where the user passes |
Usually such params has default "-1" value on the last place and it is not used. There are some cases where such parameter is not on the last position: -cv::boxFilter(src_roi, dst_roi, -1, ksize, anchor, normalize, borderType)
+cv::boxFilter(src_roi, dst_roi, CV_DEPTH_UNSPECIFIED, ksize, anchor, normalize, borderType)
There is another type of problem - local type variables which uses 'int' This may require larger changes in user code if there is no "int" overloads. But both cases are rare than "cv::Mat m(10, 10, CV_32F);" problem. |
At the same time, the newly created mat's may be initialized with |
|
@vpisarev @alalek @mshabunin I am all done with all the testing and verification. Currently, this PR works as a proof that the mutually-exclusive "Refactor *" PRs not only builds successfully, but they are collectively resolving all warnings (please note the green lights on this PR) even if |
TESTING... DO NOT MERGE!
Merge with opencv/opencv_contrib#1730 and opencv/opencv_extra#515This pullrequest changes
There are hundreds of unnamed enums, and they are being passed as int in the C++ interface.
In order to avoid passing a wrong value, and to maintain good practices, the hope is to name most of these enums, and change the int arguments into the proper enum types wherever possible.
Newly introduced enums
ElemTypefor handling the depth and channels of matrix elements (Produced byDataType<T>::typeandtraits::Type<T>::value)ElemDepthfor handling the depth of matrix elements (Produced byDataDepth<T>::typeandtraits::Depth<T>::value)MagicFlagfor handling the mixed magic values ofElemType,AccessFlagand_InputArray::KindFlagFlag enums
AccessFlagforunnamedenum havingACCESS_READas first memberunnamedenum havingDEFAULTas first memberMemoryFlagfor UMatData::unnamedenum havingCOPY_ON_MAPas first memberKindFlagfor _InputArray::unnamedenum havingKIND_SHIFTas first memberMode enums
DescriptorTypefor AKAZE::unnamedenum havingDESCRIPTOR_KAZE_UPRIGHTas first memberDetectorTypefor AgastFeatureDetector::unnamedenum havingAGAST_5_8as first memberFeatureTypefor CvFeatureParams::unnamedenum havingHAARas first memberDetectorTypefor FastFeatureDetector::unnamedenum havingTYPE_5_8as first memberMatcherTypefor DescriptorMatcher::unnamedenum havingFLANNBASEDas first memberFormatTypefor Formatter::unnamedenum havingFMT_DEFAULTas first memberHistogramNormTypefor HOGDescriptor::unnamedenum havingL2Hysas the only memberunnamedenum havingnormTypeas the only memberunnamedenum havingnormTypeas the only memberunnamedenum havingnormTypeas the only memberunnamedenum havingnormTypeas the only memberunnamedenum havingMAGIC_MASKas first memberunnamedenum havingMAGIC_VALas first memberunnamedenum havingMAGIC_VALas first memberunnamedenum havingMAGIC_MASKas first memberunnamedenum havingMAGIC_VALas first memberDiffusivityTypefor KAZE::unnamedenum havingDIFF_PM_G1as first memberScoreTypefor ORB::unnamedenum havingkBytesas first member, andkBytesbecome a static const intunnamedenum havingINTas first memberunnamedenum havingLOCATION_ROWas first memberunnamedenum havingDESCR_FORMAT_ROW_BY_ROWas first memberunnamedenum havingX_ROWas first memberNormalizationTypefor xfeatures2d::DAISY::unnamedenum havingNRM_NONEas first memberunnamedenum havingNB_SCALESas first memberDepthMaskfor _OutputArray::unnamedenum havingDEPTH_MASK_8Uas first memberTasks list
unnamedenum havingCALIB_CB_ADAPTIVE_THRESHas first memberunnamedenum havingCALIB_CB_SYMMETRIC_GRIDas first memberunnamedenum havingCALIB_USE_INTRINSIC_GUESSas first memberunnamedenum havingCAP_INTELPERC_DEPTH_GENERATORas first memberunnamedenum havingCAP_INTELPERC_DEPTH_MAPas first memberunnamedenum havingCAP_OPENNI_DEPTH_GENERATORas first memberunnamedenum havingCAP_OPENNI_DEPTH_MAPas first memberunnamedenum havingCAP_OPENNI_IMAGE_GENERATOR_PRESENTas first memberunnamedenum havingCAP_OPENNI_VGA_30HZas first memberunnamedenum havingCAP_PROP_DC1394_OFFas first memberunnamedenum havingCAP_PROP_GIGA_FRAME_OFFSET_Xas first memberunnamedenum havingCAP_PROP_GPHOTO2_PREVIEWas first memberunnamedenum havingCAP_PROP_GSTREAMER_QUEUE_LENGTHas first memberunnamedenum havingCAP_PROP_IMAGES_BASEas first memberunnamedenum havingCAP_PROP_INTELPERC_PROFILE_COUNTas first memberunnamedenum havingCAP_PROP_IOS_DEVICE_FOCUSas first memberunnamedenum havingCAP_PROP_OPENNI_OUTPUT_MODEas first memberunnamedenum havingCAP_PROP_PVAPI_MULTICASTIPas first memberunnamedenum havingCAP_PROP_XI_DOWNSAMPLINGas first memberunnamedenum havingCAP_PVAPI_DECIMATION_OFFas first memberunnamedenum havingCAP_PVAPI_FSTRIGMODE_FREERUNas first memberunnamedenum havingCAP_PVAPI_PIXELFORMAT_MONO8as first memberunnamedenum havingCASCADE_DO_CANNY_PRUNINGas first memberunnamedenum havingFM_7POINTas first memberunnamedenum havingINPAINT_NSas first memberunnamedenum havingLDR_SIZEas first memberunnamedenum havingLMEDSas first memberunnamedenum havingMOTION_TRANSLATIONas first memberunnamedenum havingNORMAL_CLONEas first memberunnamedenum havingOPTFLOW_USE_INITIAL_FLOWas first memberunnamedenum havingRECURS_FILTERas first memberunnamedenum havingSOLVEPNP_ITERATIVEas first memberunnamedenum havingUNIFORMas first memberunnamedenum havingPREFILTER_NORMALIZED_RESPONSEas first memberunnamedenum havingDISP_SHIFTas first memberunnamedenum havingMODE_SGBMas first memberunnamedenum havingORIG_RESOLas first memberunnamedenum havingNEXT_AROUND_ORGas first memberunnamedenum havingPTLOC_ERRORas first memberunnamedenum havingMODE_POSITIVEas first memberunnamedenum havingMODE_INIT_POSas first memberunnamedenum havingRETINA_COLOR_RANDOMas first memberunnamedenum havingNOas first memberunnamedenum havingNOas first memberunnamedenum havingAS_ISas first memberunnamedenum havingCALIB_USE_INTRINSIC_GUESSas first memberunnamedenum havingLINEARas first memberunnamedenum havingONE_STEPas first memberunnamedenum havingDEFAULTas first memberunnamedenum havingDEFAULT_NCLUSTERSas first memberunnamedenum havingSTART_E_STEPas first memberunnamedenum havingPINHOLEas first memberunnamedenum havingEXEC_KERNELas first memberunnamedenum havingFP_DENORMas first memberunnamedenum havingNO_CACHEas first memberunnamedenum havingNO_LOCAL_MEMas first memberunnamedenum havingTYPE_DEFAULTas first memberunnamedenum havingUNKNOWN_VENDORas first memberunnamedenum havingLOCALas first memberunnamedenum havingCALIB_USE_GUESSas first memberunnamedenum havingRECTIFY_PERSPECTIVEas first memberunnamedenum havingXYZRGBas first memberunnamedenum havingPRESET_ULTRAFASTas first memberunnamedenum havingROTATIONas first memberunnamedenum havingCACHE_SRCas first memberunnamedenum havingDECODE_3D_UNDERWORLDas first memberunnamedenum havingFTPas first memberunnamedenum havingERFILTER_NM_RGBLGradas first memberunnamedenum havingOCR_LEVEL_WORDas first memberunnamedenum havingNONEas first memberunnamedenum havingLOAD_AUTOas first memberunnamedenum havingFRAMESas first memberCurrent issues
unnamedenum havingUNDEFINEDas first memberstatic_cast<MagicFlag>()are utilized now. Proper operators needs to get enabledunnamedenum havingDEFAULT_NLEVELSas the only member to to static const int causes some Java test to fail[javac] /build/precommit_android/build/android_test/src/org/opencv/test/objdetect/HOGDescriptorTest.java:204: error: cannot find symbol [javac] assertEquals(HOGDescriptor.DEFAULT_NLEVELS, hog.get_nlevels()); [javac] ^ [javac] symbol: variable DEFAULT_NLEVELS [javac] location: class HOGDescriptor [javac] Note: Some input files use unchecked or unsafe operations. [javac] Note: Recompile with -Xlint:unchecked for details. [javac] 1 error