diff --git a/doc/mp11/set.adoc b/doc/mp11/set.adoc
index e8d708f..d57ec73 100644
--- a/doc/mp11/set.adoc
+++ b/doc/mp11/set.adoc
@@ -15,6 +15,12 @@ http://www.boost.org/LICENSE_1_0.txt
A set is a list whose elements are unique.
+## mp_is_set
+
+ template using mp_is_set = /*...*/;
+
+`mp_is_set` is `mp_true` if `S` is a set, `mp_false` otherwise.
+
## mp_set_contains
template using mp_set_contains = /*...*/;
diff --git a/include/boost/mp11/set.hpp b/include/boost/mp11/set.hpp
index a3b3b38..cd77d64 100644
--- a/include/boost/mp11/set.hpp
+++ b/include/boost/mp11/set.hpp
@@ -9,6 +9,7 @@
// http://www.boost.org/LICENSE_1_0.txt
#include
+#include
#include
namespace boost
@@ -78,6 +79,24 @@ template class L, class... U, class T1, class... T> struct mp
template using mp_set_push_front = typename detail::mp_set_push_front_impl::type;
+// mp_is_set
+namespace detail
+{
+
+template struct mp_is_set_impl
+{
+ using type = mp_false;
+};
+
+template class L, class... T> struct mp_is_set_impl>
+{
+ using type = mp_to_bool, mp_set_push_back, T...>>>;
+};
+
+} // namespace detail
+
+template using mp_is_set = typename detail::mp_is_set_impl::type;
+
} // namespace mp11
} // namespace boost
diff --git a/test/Jamfile b/test/Jamfile
index 05eefac..3396702 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -106,6 +106,7 @@ compile construct_from_tuple_cx.cpp : $(REQ) ;
run mp_set_contains.cpp : : : $(REQ) ;
run mp_set_push_back.cpp : : : $(REQ) ;
run mp_set_push_front.cpp : : : $(REQ) ;
+run mp_is_set.cpp : : : $(REQ) ;
# function
run mp_all.cpp : : : $(REQ) ;
diff --git a/test/mp_is_set.cpp b/test/mp_is_set.cpp
new file mode 100644
index 0000000..8657dc4
--- /dev/null
+++ b/test/mp_is_set.cpp
@@ -0,0 +1,73 @@
+
+// Copyright 2017 Peter Dimov.
+//
+// Distributed under the Boost Software License, Version 1.0.
+//
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main()
+{
+ using boost::mp11::mp_list;
+ using boost::mp11::mp_is_set;
+ using boost::mp11::mp_true;
+ using boost::mp11::mp_false;
+
+ {
+ BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same, mp_false>));
+ }
+
+ {
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ }
+
+ {
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ }
+
+ {
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_true>));
+ BOOST_TEST_TRAIT_TRUE((std::is_same>, mp_false>));
+ }
+
+ return boost::report_errors();
+}