Home > Software design >  How to make concept that checks type equality for any templated type in C ?
How to make concept that checks type equality for any templated type in C ?

Time:11-17

In C you can make concepts that check for specific type equality:

template<typename T> concept Int = std::is_same_v<T, int>;
template<typename T> concept String = std::is_same_v<T, std::string>;

Is it possible to make a concept that checks for type equality of any type, so I could make templates looking something like this:

template<ValidType<int>... Ints> void passInts(Ints... ints) {}
template<ValidType<std::string>... Strings> void passStrings(Strings... strings) {}

That way I would only need to write a single concept checking for type equality. I know I could use conjunction for this but I think concepts are much cleaner.

CodePudding user response:

I mean, you could write a concept to do that. Or you could just use std::same_as:

template<std::same_as<int>... Ints> void passInts(Ints... ints)
template<std::same_as<std::string>... Strings> void passStrings(Strings... strings)

When a concept is used against a template parameter pack, it is applied individually to each of the types in the pack.

Of course, this may not quite do what you need. The reason being that same_as is very serious about its name. If you want to invoke perfect forwarding through forwarding references, template argument deduction can start deducing the types as references to T. Which re not the "same_as" T.

So if you want to allow for perfect forwarding, you need a different concept: similar_to. Which sadly is not in the standard library, despite how simple and useful it is:

template<typename T1, typename T2>
concept similar_to = std::same_as<std::remove_cvref_t<T1>, T2>;

Note that this assumes that T2 has no reference or cv qualifiers. You can make a version that removes cvref from both.

Now, you can do this:

template<similar_to<int> ...Ints> void passInts(Ints && ...ints)
template<similar_to<std::string> ...Strings> void passStrings(Strings && ...strings)

And now you get perfect forwarding back.

CodePudding user response:

Not sure I understand exactly what you want but you can add the type you want to check for as second template parameter:

template<typename T, typename U> concept ValidType = std::is_same_v<T, U>;

Then your two examples will work in that all template arguments will be restricted to int or std::string respectively.

In fact that is exactly what the std::same_as concept from the standard library already does. So just use that instead of ValidType to get additional benefits of constraint subsumption lacking in the simple variant above.

  • Related