Since this question is pretty old (from 2011) and concepts were recently released as of this writing (2020), I would like to clarify a couple of things, just to not mislead people or discourage them from using concepts.
Concepts that used to be considered and concepts being released now are quite different beings. Concepts released in C++20 are also known as “concepts lite” as they include reduced features compared to the initial design of concepts. So, what was taken away from concepts?
The main difference is that the primary design of concepts was intended for checking not only the correctness of the usage of a template but also the correctness of the definition of this template. For example, suppose you have a template with type Animal, that needs to have the member function make_sound. You can imagine a constrained function template like so:
template <typename Animal>
requires requires(Animal& x){
x.make_sound();
}
int animal_tricks(Animal& x) {
x.make_sound();
x.do_trick();
}
Now, with the initial design of concepts, the definition of the function template animal_tricks would be incorrect because we are using a do_trick member function, which was not part of the required expression. With C++20 concepts lite, this definition of concept is fine. The compiler will not check the correctness of the animal_tricks function template because, in a concepts-lite world, it’s up to the developer to correctly specify the requirements on the type.
That difference can make quite a big difference in the compilation time. In 2016, there were two papers that considered the reasons for concepts to enter C++17 or not:
“Why I want Concepts, and why I want them sooner rather than later” and
“Why I want Concepts, but why they should come later rather than sooner.”
Neither even considered performance, so it’s a good indicator that it was not an issue back then.
Also, the current concepts design might come with some performance advantages. According to the rule of Chiel, the slowest thing in compilation is SFINAE because it needs to at least try to instantiate (usually) a significant amount of types, only to abandon them later on. Concepts (depending on how they are implemented) might not need to instantiate any templates, which in fact might end up being a performance advantage.