Reputation: 1057
I'm trying to provide a hash<>
specialization for a family of types I've been working on. So far so good, the specialization itself is easy to provide, I've already done similar things for numeric_limits<>
. But I'm facing the problem of how to provide the specialization in a way that is portable to C++11 and -pre-11 (C++03 or whatever).
The problem I'm bumping on, of course, is that hash<>
can be defined in one of several namespaced, and I'm forced to provide the specialization in the same namespace.
// in c++11
namespace std { struct hash<>...; }
// in c++03 this is one possibility
namespace std { namespace tr1 { struct hash<>...; } }
// my library's specialization
namespace ????_open {
struct hash<mytype>...;
????_close
Of course, one option would be using #defines to reach, open and close the adequate namespaces, or providing N files with N different specializations and conditionally #include the correct one, but that's cumbersome:
#if defined(some_c++11_condition)
#include "c++11-specialization.h"
#elif defined(some_c++03_condition)
#include "c++03-specialization.h"
#elif (some_other_condition)
#oh_dear_who_knows_what_this_include_will_be_like
#else_ad_nauseam
#endif
Of course, I'll be sticking to that strategy if I'm forced to but I wanted to explore some other options before. In particular, I though I could use namespace alias to specialize in the correct place:
#if defined(some_c++11_condition)
namespace std_specialize = std;
#elif defined(some_c++03_condition)
namespace std_specialize = std::tr1;
#...
#endif
...
namespace std_specialize {
struct hash<mytype>...;
}
Unfortunately this doesn't work in any of the 3 compilers I have tried (MSVC 2008, GCC 4.7, Clang 3.0) with various errors regarding "declaration of namespace conflicts with...
" in the line that reopens the namespace, which shouldn't happen because namespaces can be reopened multiple times, and if an alias is an alias and not something else then this should also apply for them.
So, is a namespace alias really an alias, or a misnomer meaning something else? Or is there other reason why I can not specialize this way? If so, any other method (better than barrages of #defines)?
Upvotes: 3
Views: 377
Reputation:
Proper macros:
// Defined before
// #define NOEXCEPT noexcept
#include <iostream>
#if TR1_CONDITION
// tr1
#define HASH_NAMESPACE std::tr1
#define HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
#define HASH_NAMESPACE_END }}
#else
// std
#define HASH_NAMESPACE std
#define HASH_NAMESPACE_BEGIN namespace std {
#define HASH_NAMESPACE_END }
#endif
namespace X {
struct Class {};
}
HASH_NAMESPACE_BEGIN
template<>
struct hash<X::Class> {
size_t operator()(const X::Class&) const NOEXCEPT { return 123; }
};
HASH_NAMESPACE_END
int main() {
HASH_NAMESPACE::hash<X::Class> h;
std::cout << h(X::Class()) << std::endl;
return 0;
}
(But all of it is not nice)
Upvotes: 0
Reputation: 109119
Yes, a namespace
alias is really an alias. The error is occurring because you're declaring std_specialize
as an alias for either std
or std::tr1
and then trying to declare a namespace
with the same name. If it were legal, after that declaration, what would std_specialize
refer to, std
(or std::tr1
) or the new namespace containing your hash
specialization?
What you probably want to do is
namespace std {
#if __cplusplus < 201103L
namespace tr1 {
#endif
template<>
struct hash<my_type> { ... };
#if __cplusplus < 201103L
}
#endif
}
Upvotes: 1