Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require C++20 and update to C++20 #698

Open
wants to merge 25 commits into
base: master
Choose a base branch
from

Conversation

jmcarcell
Copy link
Member

@jmcarcell jmcarcell commented Oct 18, 2024

Since the Key4hep stack and the LCG stack are both on C++20 for some time, we could start using C++20 features. This PR changes the requirements and uses in some places C++20 features.

BEGINRELEASENOTES

  • Simplify template code by using concept and require when possible. In some places like the UserDataCollection and GenericParameters it seems that cppyy (3.1.2 with ROOT 6.32.06) doesn't like requires nor concept so they can't be changed for now.
  • Use consteval when possible which, unlike constexpr, guarantees evaluation at compile-time
  • Remove checks for versions above or below C++20 for the standard
  • Use algorithms from std::ranges like std::ranges::find and std::ranges::sort
  • Remove the ubuntu workflows since they are built on C++17

ENDRELEASENOTES

Copy link
Collaborator

@tmadlener tmadlener left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am generally very in favor of this. I am not yet entirely sure how to properly reflect this in the podio version. Strictly speaking it could be a breaking change, since we remove a "feature". I think we should at least put some warning / message into a podio tag to check if someone is still building podio with c++17 (and can't easily upgrade to c++20).

We potentially have to change a few of the LCG stacks that we use to have the necessary compiler (and ROOT) support.

Copy link
Collaborator

@tmadlener tmadlener left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we potentially also have to have a discussion about some style rules around concepts, e.g. do we always use

template<typename T>
requires Concept<T>

or do we go to

template<Concept T>

where possible and only fall back to using requires when necessary?

CMakeLists.txt Show resolved Hide resolved
include/podio/utilities/TypeHelpers.h Outdated Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose gcc11 doesn't yet have enough support for the features that we need?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ROOT being built with C++17 and the check failing, I'm quite sure otherwise it would pass. I think Ubuntu24 will be there soon so maybe we can check in a few days.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right. In that case we could potentially add an ubuntu workflow based on a key4hep stack?

cmake/podioConfig.cmake.in Show resolved Hide resolved
@jmcarcell
Copy link
Member Author

I am generally very in favor of this. I am not yet entirely sure how to properly reflect this in the podio version. Strictly speaking it could be a breaking change, since we remove a "feature". I think we should at least put some warning / message into a podio tag to check if someone is still building podio with c++17 (and can't easily upgrade to c++20).

We potentially have to change a few of the LCG stacks that we use to have the necessary compiler (and ROOT) support.

I have opened another PR (#700) with a warning when building with C++17 for a future tag.

I think we potentially also have to have a discussion about some style rules around concepts, e.g. do we always use

template<typename T>
requires Concept<T>

or do we go to

template<Concept T>

where possible and only fall back to using requires when necessary?

I am against always using a Concept when possible. I think this should be something that can be reused in several places and I think for the ones created in this PR this is the case. Otherwise it becomes very hard to read if for every template you have to find out what the concept being used means. In the case when we have a reusable concept then I prefer the shorter one.

CMakeLists.txt Outdated Show resolved Hide resolved
@m-fila
Copy link
Contributor

m-fila commented Nov 5, 2024

I am against always using a Concept when possible. I think this should be something that can be reused in several places and I think for the ones created in this PR this is the case. Otherwise it becomes very hard to read if for every template you have to find out what the concept being used means. In the case when we have a reusable concept then I prefer the shorter one.

Core guidelines advise to always constrain template with concepts
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#t10-specify-concepts-for-all-template-arguments
and to use shorter notation for simple requirements and fallback to require when && or || of concepts are used
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#t13-prefer-the-shorthand-notation-for-simple-single-type-argument-concepts

I think the idea with using concepts everywhere is about using std concepts or building complex concepts with logic operators from them (not about introducing a separate, dedicated concept for every template argument). But I agree that introducing this policy here would be cumbersome

README.md Outdated Show resolved Hide resolved
doc/links.md Outdated
Comment on lines 200 to 202
template <typename FromU>
requires(Mutable&& std::is_same_v<detail::GetDefaultHandleType<FromU>, FromT>&&
detail::isDefaultHandleType<FromU>) void setFrom(FromU value);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting here should match the one in the source code

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated after setting C++20 in .clang-format

Comment on lines 27 to 38
class RNTupleReader;
class RNTupleWriter;
} // namespace podio
#endif

namespace podio {

#if !defined(__CLING__)
// cling doesn't really deal well (i.e. at all in this case) with the forward
// declaration here and errors out, breaking e.g. python bindings.
class ROOTReader;
#endif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand why these can be removed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see the friends are needed and I was suspicious about if checking for __CLING__ was needed and it seems it's not. ROOTReader is not being used in this header.

Comment on lines 143 to 151
#if PODIO_ENABLE_RNTUPLE
friend RNTupleReader;
friend RNTupleWriter;
#endif

#if !defined(__CLING__)
friend ROOTReader;
#endif

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, these changes if they are possible seem to be unrelated to the c++17 to c++20 changes (for me). If they are independent we should move them to another PR, I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to #706

template <typename DefT, template <typename...> typename Op, typename... Args>
using detected_or = detail::detector<DefT, void, Op, Args...>;

template <template <typename...> typename Op, typename... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is removed, because it's unused, I suppose?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, only used in GetCollectionType that is also removed because it's unused.

Comment on lines 148 to 150
template <typename FromU>
requires(Mutable&& std::is_same_v<detail::GetMutableHandleType<FromT>, FromU>&&
detail::isMutableHandleType<FromU>) void setFrom(FromU value) {
Copy link
Collaborator

@tmadlener tmadlener Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
template <typename FromU>
requires(Mutable&& std::is_same_v<detail::GetMutableHandleType<FromT>, FromU>&&
detail::isMutableHandleType<FromU>) void setFrom(FromU value) {
template <typename FromU>
requires(Mutable && std::is_same_v<detail::GetMutableHandleType<FromT>, FromU> &&
detail::isMutableHandleType<FromU>)
void setFrom(FromU value) {

Does this formatting get past clang-format? I think this would be much more readable than the current form. Or do we have to update our .clang-format?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the format to C++20 and it looks better now

@tmadlener
Copy link
Collaborator

Core guidelines advise to always constrain template with concepts https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#t10-specify-concepts-for-all-template-arguments and to use shorter notation for simple requirements and fallback to require when && or || of concepts are used https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#t13-prefer-the-shorthand-notation-for-simple-single-type-argument-concepts

I think the idea with using concepts everywhere is about using std concepts or building complex concepts with logic operators from them (not about introducing a separate, dedicated concept for every template argument). But I agree that introducing this policy here would be cumbersome

So on a quick glance we are somewhat following this already and we could just quote this as a general (albeit a bit vague) guideline?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants