Date: Fri, 8 Dec 2023 14:46:21 +0800
There are quite a few specialization points in the std namespace that
a user-defined type can leverage, e.g.:
- std::hash (for use as key in the unordered associative containers)
- std::is_error_code_enum (to act like an error code)
- std::tuple_size and std::tuple_element (to be tuple-like)
Unfortunately, specialization of such templates requires quitting the
current namespace and adding specialization at the global or std
namespace, which is extremely inconvenient.
namespace MyNamespace {
struct MyClass {
…
};
} // Quitting the current namespace
template <>
::std::hash<MyNamespace::MyClass> {
…
};
namespace MyNamespace {
// Continue the work in MyNamespace
}
I know (starting from private communications with Arthur O'Dwyer) that
Mike Spertus had a proposal nearly 10 years ago.
https://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3867.html
Is it something worth revisiting? We can just follow exactly the same
rule, and make specialization inside MyNamespace has exactly the same
effect as exiting to the global namespace.
GPT wrongly suggested the following code:
// Global namespace
template<typename T>
struct is_special_enum : std::false_type {};
// in namespace foo
namespace foo {
enum class MySpecialEnum1 {};
// specializations for the enums you care about
template <>
struct ::is_special_enum<MySpecialEnum1> : std::true_type {};
} // namespace foo
It does not compile, except under MSVC. However, even under MSVC, you
can only specialize a parent-scope template, but not an unrelated one
like std::is_error_code_enum....
Another issue Mike mentioned was how names should be resolved in the
specialization: should we choose first a symbol in the "current"
namespace, or a symbol in the "specialized" namespace? I do not hold a
strong opinion here, but either solution seems better than having to
exit to the global namespace.
(Personally, I feel the "current" namespace is more intuitive for name
resolution. However, using the "specialized" namespace allows easy
transformation of code.)
Any comments?
a user-defined type can leverage, e.g.:
- std::hash (for use as key in the unordered associative containers)
- std::is_error_code_enum (to act like an error code)
- std::tuple_size and std::tuple_element (to be tuple-like)
Unfortunately, specialization of such templates requires quitting the
current namespace and adding specialization at the global or std
namespace, which is extremely inconvenient.
namespace MyNamespace {
struct MyClass {
…
};
} // Quitting the current namespace
template <>
::std::hash<MyNamespace::MyClass> {
…
};
namespace MyNamespace {
// Continue the work in MyNamespace
}
I know (starting from private communications with Arthur O'Dwyer) that
Mike Spertus had a proposal nearly 10 years ago.
https://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3867.html
Is it something worth revisiting? We can just follow exactly the same
rule, and make specialization inside MyNamespace has exactly the same
effect as exiting to the global namespace.
GPT wrongly suggested the following code:
// Global namespace
template<typename T>
struct is_special_enum : std::false_type {};
// in namespace foo
namespace foo {
enum class MySpecialEnum1 {};
// specializations for the enums you care about
template <>
struct ::is_special_enum<MySpecialEnum1> : std::true_type {};
} // namespace foo
It does not compile, except under MSVC. However, even under MSVC, you
can only specialize a parent-scope template, but not an unrelated one
like std::is_error_code_enum....
Another issue Mike mentioned was how names should be resolved in the
specialization: should we choose first a symbol in the "current"
namespace, or a symbol in the "specialized" namespace? I do not hold a
strong opinion here, but either solution seems better than having to
exit to the global namespace.
(Personally, I feel the "current" namespace is more intuitive for name
resolution. However, using the "specialized" namespace allows easy
transformation of code.)
Any comments?
-- Yongwei Wu URL: http://wyw.dcweb.cn/
Received on 2023-12-08 06:46:34