I've reduced this as much as I can. Test case below. The two static asserts are testing the same thing, AFAICT. One tests the Function concept directly, the other tests it indirectly through a __function trait that has been constrained with Function. The former succeeds while the latter fails. Somewhat mysterious. namespace std { typedef unsigned int size_t; typedef int ptrdiff_t; typedef decltype(nullptr) nullptr_t; template<typename _Tp, _Tp... _Idx> struct integer_sequence { typedef _Tp value_type; static constexpr size_t size() { return sizeof...(_Idx); } }; template <class T, T Value> struct integral_constant { using type = integral_constant; using value_type = T; constexpr operator T() const { return Value; } constexpr T operator()() const { return Value; } static constexpr T value {Value}; }; template <class T, T Value> constexpr T integral_constant<T, Value>::value; using true_type = integral_constant<bool, true>; using false_type = integral_constant<bool, false>; template <class T, class U> struct is_same : false_type {}; template <class T> struct is_same<T,T> : true_type {}; } namespace meta { inline namespace v1 { template <typename T> using _t = typename T::type; template <bool... Bools> using and_c = std::is_same<std::integer_sequence<bool, Bools...>, std::integer_sequence<bool, (Bools || true)...>>; } } namespace stl2 { inline namespace v1 { using std::declval; namespace detail { template <class...> struct all_same : std::true_type {}; template <class T, class...Rest> struct all_same<T, Rest...> : meta::and_c<__is_same_as(T, Rest)...> {}; } template <class...Ts> concept bool Same() { return detail::all_same<Ts...>::value; } template <class F, class...Args> using ResultType = decltype(declval<F>()(declval<Args>()...)); template <class> struct value_type {}; template <class T> struct value_type<T*> { using type = T; }; template <class T> using ValueType = typename value_type<T>::type; template <class F, class...Args> concept bool Function() { return requires (F& f, Args&&...args) { f((Args&&)args...); requires Same<decltype(f((Args&&)args...)), ResultType<F, Args...> >(); }; } template <class, class...> struct __function : std::false_type {}; Function{F, ...Args} struct __function<F, Args...> : std::true_type {}; template <class F, class I1, class I2> concept bool IndirectCallable() { return Function<F, ValueType<I1>, ValueType<I2>>(); } template <class F, class I1, class I2> concept bool IndirectCallable2() { return __function<F, ValueType<I1>, ValueType<I2>>::value; } namespace ext { namespace models { template <class, class, class> constexpr bool indirect_callable() { return false; } IndirectCallable{F, I1, I2} constexpr bool indirect_callable() { return true; } template <class, class, class> constexpr bool indirect_callable2() { return false; } IndirectCallable2{F, I1, I2} constexpr bool indirect_callable2() { return true; } }} }} namespace models = stl2::ext::models; template <class T = void> struct plus { T operator()(T, T) const; }; static_assert((models::indirect_callable<::plus<int>, int*, int*>()), "Concept check failed: " "models::indirect_callable<::plus<int>, int*, int*>()"); static_assert((models::indirect_callable2<::plus<int>, int*, int*>()), "Concept check failed: " "models::indirect_callable2<::plus<int>, int*, int*>()");
If I replace the variadic Same concept with the binary one below, the problem goes away. template<class T, class U> concept bool Same() { return __is_same_as(T,U); }
Here's a somewhat minimized test case that illustrates that overload resolution works correctly, but matching partial specializations of a class template or variable template does not: template <bool Value> struct bool_ { static constexpr bool value {Value}; }; using true_type = bool_<true>; using false_type = bool_<false>; template <class...> struct all_same : true_type {}; template <class T, class...Rest> struct all_same<T, T, Rest...> : all_same<T, Rest...> {}; template <class T, class U, class...Rest> struct all_same<T, U, Rest...> : false_type {}; template <class...Ts> concept bool Same() { return all_same<Ts...>::value; } template <class F, class...Args> concept bool Function() { return requires (F& f, Args&&...args) { requires Same<int, decltype(f((Args&&)args...))>(); }; } template <class, class...> constexpr bool function() { return false; } Function{F, ...Args} constexpr bool function() { return true; } template <class, class...> constexpr bool func_v = false; Function{F, ...Args} constexpr bool func_v<F, Args...> = true; template <class, class...> struct is_function : false_type {}; Function{F, ...Args} struct is_function<F, Args...> : true_type {}; struct plus { int operator()(int) const; }; static_assert(function<::plus, int>()); // Fine static_assert(func_v<::plus, int>); // Error static_assert(is_function<::plus, int>::value); // Error
This seems to have been fixed at some point. All examples compile in the concepts-cxx2a branch, which also has a test for this PR.
This be closed now that concepts-cxx2a has been merged to trunk.