I am trying to write a program that sort only numbers in a std::vector or a std::list for which I did 2 concepts:
template<typename T>
concept ValidContainer = requires(T a) {
std::same_as<T, std::vector<typename T::value_type>>;
std::same_as<T, std::list<typename T::value_type>>;
};
And:
template<typename T>
concept Sortable = requires(T a) {
ValidContainer<T> && std::same_as<typename T::value_type, int>;
ValidContainer<T> && std::same_as<typename T::value_type, float>;
};
And the signature of the function that sorts them:
void BubbleSort(Sortable auto& collection)
{
// sort algorithm
}
The question that arises in my head is when I pass a std::vector<std::string>
it does not show me a compilation error?
int main()
{
std::vector<int> test = { 32, 3, 6, 8, 2, 5, 0, 43, 67, 1 };
std::vector<std::string> test2 = { "first", "second", "third" };
BubbleSort(test); // this is ok
BubbleSort(test2); // shouldn't this be a compile error?
return 0;
}
CodePudding user response:
This:
template<typename T>
concept ValidContainer = requires(T a) {
std::same_as<T, std::vector<typename T::value_type>>;
std::same_as<T, std::list<typename T::value_type>>;
};
is checking to see if the expression std::same_as<T, std::vector<typename T::value_type>>;
is valid, not that it also is true
. Which is to say, it's basically just checking that typename T::value_type
is a thing.
In that form, if you want to require something, you have to use requires
:
template<typename T>
concept ValidContainer = requires(T a) {
requires std::same_as<T, std::vector<typename T::value_type>>;
requires std::same_as<T, std::list<typename T::value_type>>;
};
Although now we're requiring that T
is both a vector
and a list
, so that's never going to be true. So really we need:
template <typename T>
concept ValidContainer =
std::same_as<T, std::vector<typename T::value_type>>
|| std::same_as<T, std::list<typename T::value_type>>;
Although even this isn't great because now we're rejecting std::vector<T, MyAlloc>
.
This is separate from the question of why this is your constraint - why can you only sort vector
and list
... but not like deque
or string
or span
or ... ? Or why you're limiting to just int
and float
?
You can bubble sort any forward range that is orderable. Which I would express as:
template <std::ranges::forward_range R>
requires std::totally_ordered<std::ranges::range_reference_t<R>>
void BubbleSort(R& r);
CodePudding user response:
requires
expressions are true
if the enclosed expressions are well-formed. It does not matter if the expressions themselves evaluate to true
.
(In fact, the expressions in a requires-expression are never evaluated)
You don't seem to be solving a problem that tests if an expression is well-formed. Your concepts should look like this:
template<typename T>
concept ValidContainer =
std::same_as<T, std::vector<typename T::value_type>> ||
std::same_as<T, std::list<typename T::value_type>>;
template<typename T>
concept Sortable =
( ValidContainer<T> && std::same_as<typename T::value_type, int> ) ||
( ValidContainer<T> && std::same_as<typename T::value_type, float> );