I'm trying to learn about Concepts Lite TS, which has not yet been merged into the standard. I got confused in the behavior of short-circuited disjunctions in conceptual bodies.
Here is a small example:
#include <type_traits> #include <iostream> template <typename T, typename ... Ts> concept bool myconcept = (sizeof...(Ts) == 0) || (std::is_same_v<T, std::common_type_t<Ts...>>); template <typename ... Ts> void myfunc(Ts ... args) requires myconcept<int, Ts...> { (... , (std::cout << args << std::endl)); } int main() { myfunc(); return 0; }
Compiling with gcc 7.1 and -fconcepts gives an error:
error: cannot call function 'void myfunc(Ts ...) requires myconcept<int, Ts ...> [with Ts = {}]'
In this example, std::common_type_t<Ts...> does not exist, since struct std::common_type<Ts...> does not have a type member if Ts = {} . However, I think this should compile because the cppereference.com documentation in terms and conditions states that
Deviations are evaluated from left to right and shorted (if the left constraint is satisfied, then the output of the template argument to the right constraint is not taken).
Since sizeof...(Ts) == 0 is executed, the output of the template argument should not be performed in the second constraint, and the requirement myconcept<int, Ts...> must be satisfied.
It is strange that placing requirements directly in the function declarator leads to compilation of the program:
#include <type_traits> #include <iostream> template <typename ... Ts> void myfunc(Ts ... args) requires (sizeof...(Ts) == 0) || (std::is_same_v<int, std::common_type_t<Ts...>>) { (... , (std::cout << args << std::endl)); } int main() { myfunc(); return 0; }
Is there a good explanation for this behavior? Thanks.