I want to specialize std::formatter
inside my namespace. However, this does not work as I want to (variant 1). It works outside the namespace (variant 3) as well as with a workaround inside the namespace (variant 2).
#include <format>
#include <iostream>
#include <string>
#include <type_traits>
class Class {};
#define VARIANT 1
namespace Namespace {
#if VARIANT == 1
template <>
struct std::formatter<Class> : std::formatter<std::string> {
auto format(const Class& Class, auto& context) const {
return std::formatter<std::string>::format("CLASS", context);
}
};
#endif
#if VARIANT == 2
template <typename T>
requires std::same_as<T, Class>
struct std::formatter<T> : std::formatter<std::string> {
auto format(const Class& Class, auto& context) const {
return std::formatter<std::string>::format("CLASS", context);
}
};
#endif
} // namespace Namespace
#if VARIANT == 3
template <>
struct std::formatter<Class> : std::formatter<std::string> {
auto format(const Class& Class, auto& context) const {
return std::formatter<std::string>::format("CLASS", context);
}
};
#endif
int main() { std::cout << std::format("{}", Class()) << std::endl; }
This is on x64 msvc v19.40 VS17.10. gcc compiles only variant 3.
So my questions are, what are standard-conforming, portable ways of specialing std::formatter
inside namespaces (or generally)?
So my questions are, what are standard-conforming, portable ways of specialing
std::formatter
inside namespaces (or generally)?
There aren't any.
You can only specialize a class template in places in which you can define the primary template. That is, you either have to do this (at global scope):
template <>
struct std::formatter<MyClass> { ... };
Or you do this (within std
):
namespace std {
template <>
struct formatter<MyClass> { ... };
}
But you cannot do this or anything like it:
namespace N {
template <>
struct ::std::formatter<MyClass> { ... };
}
More generally, given something like:
namespace N::M {
template <class T> struct C;
}
All of these are fine:
template <> struct N::M::C<int> { }; // ok
namespace N { template <> struct M::C<double> { }; } // ok
namespace N::M { template <> struct C<float> { }; } // ok
N::M::C<int> a; // ok
N::M::C<double> b; // ok
N::M::C<float> c; // ok
But not anywhere else.