Move has_formatter into the public fmt namespace.
This will allow users to do SFINAE-friendly checks for
the formattability of a type.

Fixes #1369
{"label": "fmtlib:master", "ref": "master", "sha": "1f918159edded99c9c0cf005c96ecc12e4cc92b1"}
Is there a way to detect if a type is formattable in a way that is SFINAE-friendly?  I am familiar with the `static_assert` that triggers inside fmt in this case, but is there a SFINAE-friendly way?  Thanks
Detect if type is formattable in SFINAE-friendly way?
diff --git a/include/fmt/core.h b/include/fmt/core.h
index 02a389fa0763..68b022a50ea5 100644
--- a/include/fmt/core.h
+++ b/include/fmt/core.h
@@ -541,14 +541,14 @@ struct FMT_DEPRECATED convert_to_int
     : bool_constant<!std::is_arithmetic<T>::value &&
                     std::is_convertible<T, int>::value> {};
 
-namespace internal {
-
 // Specifies if T has an enabled formatter specialization. A type can be
 // formattable even if it doesn't have a formatter e.g. via a conversion.
 template <typename T, typename Context>
 using has_formatter =
     std::is_constructible<typename Context::template formatter_type<T>>;
 
+namespace internal {
+
 /** A contiguous memory buffer with an optional growing ability. */
 template <typename T> class buffer {
  private:

diff --git a/test/core-test.cc b/test/core-test.cc
index acfd2cd08a22..c37060022564 100644
--- a/test/core-test.cc
+++ b/test/core-test.cc
@@ -453,11 +453,11 @@ template <> struct formatter<enabled_formatter> {
 FMT_END_NAMESPACE
 
 TEST(CoreTest, HasFormatter) {
-  using fmt::internal::has_formatter;
+  using fmt::has_formatter;
   using context = fmt::format_context;
-  EXPECT_TRUE((has_formatter<enabled_formatter, context>::value));
-  EXPECT_FALSE((has_formatter<disabled_formatter, context>::value));
-  EXPECT_FALSE((has_formatter<disabled_formatter_convertible, context>::value));
+  static_assert(has_formatter<enabled_formatter, context>::value, "");
+  static_assert(!has_formatter<disabled_formatter, context>::value, "");
+  static_assert(!has_formatter<disabled_formatter_convertible, context>::value, "");
 }
 
 struct convertible_to_int {
diff --git a/test/format-test.cc b/test/format-test.cc
index 61b893c4b99e..0dce6bad596e 100644
--- a/test/format-test.cc
+++ b/test/format-test.cc
@@ -1974,8 +1974,8 @@ enum TestEnum { A };
 TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); }
 
 TEST(FormatTest, FormatterNotSpecialized) {
-  EXPECT_FALSE((fmt::internal::has_formatter<fmt::formatter<TestEnum>,
-                                             fmt::format_context>::value));
+  static_assert(!fmt::has_formatter<fmt::formatter<TestEnum>,
+                                    fmt::format_context>::value, "");
 }
 
 #if FMT_HAS_FEATURE(cxx_strong_enums)

{"locale-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "compile-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ostream-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ranges-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "core-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "scan-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "color-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "grisu-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "chrono-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "gtest-extra-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "posix-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "assert-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "posix-mock-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "printf-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-impl-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "custom-formatter-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"locale-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "compile-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ostream-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ranges-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "core-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "scan-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "color-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "grisu-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "chrono-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "gtest-extra-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "posix-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "assert-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "posix-mock-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "printf-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-impl-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "custom-formatter-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"passed_count": 17, "failed_count": 0, "skipped_count": 0, "passed_tests": ["format-test", "gtest-extra-test", "locale-test", "compile-test", "posix-test", "ostream-test", "ranges-test", "assert-test", "posix-mock-test", "core-test", "printf-test", "color-test", "scan-test", "format-impl-test", "grisu-test", "custom-formatter-test", "chrono-test"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 0, "failed_count": 0, "skipped_count": 0, "passed_tests": [], "failed_tests": [], "skipped_tests": []}
{"passed_count": 17, "failed_count": 0, "skipped_count": 0, "passed_tests": ["format-test", "gtest-extra-test", "locale-test", "compile-test", "posix-test", "ostream-test", "ranges-test", "assert-test", "posix-mock-test", "core-test", "printf-test", "color-test", "scan-test", "format-impl-test", "grisu-test", "custom-formatter-test", "chrono-test"], "failed_tests": [], "skipped_tests": []}