I thought I wrote a nice concept, but then before the commit I reordered where it was in my file and suddenly, the program result was wrong (without any compilation errors)!
Here's a code sample to match what I had, trying to do a special compare in some cases:
#include <iostream>
#include <string>
#include <vector>
namespace
{
//Put CanDoSpecialCompare here, and the end result is different ("Same int, Different vector"))!
template<typename T>
bool SpecialCompare(const std::vector<T>& first, const std::vector<T>& second) {
return true; //Dummy implementation
}
//Put CanDoSpecialCompare here, and the end result is different ("Same int, Same vector"))!
template <typename T>
concept CanDoSpecialCompare = requires(T a, T b) {
SpecialCompare(a,b);
};
template<CanDoSpecialCompare T>
bool Compare(const T& a, const T& b) {
return SpecialCompare(a, b);
}
template<typename T>
bool Compare(const T& a, const T& b) {
return a == b;
}
}
int main() {
std::vector<int> v1{1,2}, v2{1,3};
int i1 = 1, i2 = 1;
if (Compare(i1,i2))
std::cout << "Same int, ";
else
std::cout << "Different int, ";
if (Compare(v1,v2))
std::cout << "Same vector" << std::endl;
else
std::cout << "Different vector" << std::endl;
}
I sort of see why this happens (defining the concept before the function it tests for, so it doesn't "see" the function?), but not completely (it's a template that is used only after the SpecialCompare function template it needs, so at the moment I use the concept, it should see the SpecialCompare function template?).
Also, what could I do if I wanted to have the concept at the top, or better, how can I write this so that the concept can be moved without issue? I think I could also use a trait, but my impression was always that concepts were the more readable/shorter equivalent of that?
As already mentioned in comments, the concept can only see names declared before itself, or introduced by ADL - and name lookup failure just counts as evaluating to false
(after all, there could be a SpecialCompare
introduced via ADL for some T
).
The easy solution is to add a sanity check such as
template <typename T>
concept CanDoSpecialCompare = requires(T a, T b) {
SpecialCompare(a,b);
};
static_assert(CanDoSpecialCompare<std::vector<int>>);
right after the concept.