[multi_index] function object as key extractor?
As I find myself replacing all kind of C++ standard containers with multi_index_container (a really very useful container) I've been defining key extractors quite a lot and wonder if there is any shortcut like using lambda expressions or function objects. Here's some pseudo-code to explain what I mean: struct foo { std::string s; foo(std::string s) : s(s) { } }; typedef multi_index_container< foo, indexed_by< hashed_unique< boost::bind<std::size_t, &std::string::size, member<foo, std::string, &foo::s> > > >
mi_t;
The idea is to call another function on the object which is returned by the key extractor member. Here in this example the multi_index_container would only store strings with a unique size. However I'm lost how to define the key extractor. The difficulty is probably that I normally don't need to specify types when I use boost::bind or lambda expressions. Now I need to figure out how to use them with multi_index_container - is there any trick or I better go on defining key extractors? Boris
Hello Boris, Boris ha escrito:
As I find myself replacing all kind of C++ standard containers with multi_index_container (a really very useful container) I've been defining key extractors quite a lot and wonder if there is any shortcut like using lambda expressions or function objects. Here's some pseudo-code to explain what I mean:
struct foo { std::string s; foo(std::string s) : s(s) { } };
typedef multi_index_container< foo, indexed_by< hashed_unique< boost::bind<std::size_t, &std::string::size, member<foo, std::string, &foo::s> > > >
mi_t;
The idea is to call another function on the object which is returned by the key extractor member. Here in this example the multi_index_container would only store strings with a unique size. However I'm lost how to define the key extractor. The difficulty is probably that I normally don't need to specify types when I use boost::bind or lambda expressions. Now I need to figure out how to use them with multi_index_container - is there any trick or I better go on defining key extractors?
Well, you can approach to what you want if your compiler provides a typeof() facility. If this is the case, a first attempt to define your key extractor based on boost::bind could be like this: typedef multi_index_container< foo, indexed_by< hashed_unique< typeof(boost::bind(&std::string::size,boost::bind(&foo::s,_1))) > >
mi_t;
which unfortunately does *not* work because of the following: the type typeof(expr) (with "expr" standing for the boost::bind expression above) is not default constructible, which the usual usage of key extractors assumes, i.e., the following does not compile: typeof(expr) x; But the following does actually work: typeof(expr) x(expr); which can be leveraged to define our boost::bind-based extractor, albeit by resorting to an out-of-typedef definition: #define DEFINE_BIND_TYPE(name,expr) \ typedef boost::remove_reference< \ boost::remove_cv<typeof(expr)>::type>::type name##_expr_type; \ \ struct name:name##_expr_type \ { \ name():name##_expr_type(expr){} \ }; DEFINE_BIND_TYPE( extractor, boost::bind(&std::string::size,boost::bind(&foo::s,_1))) typedef multi_index_container< foo, indexed_by< hashed_unique<extractor> >
mi_t;
Whether this is more convenient than writing your own key extractors is a debatable issue... One final warning: this trick relies on an undocumented feature of boost::bind, namely that the function objects produced by this lib own a result_type nested typedef, as required by the key extractor concept --otherwise the classes defined by DEFINE_BIND_TYPE wouldn't be conformant key extractors. So, if you want to stand on the documented side you couldn't use this. Also, this is one reason why thes idiom does not extend to boost::lambda expressions. The attached snippet compiles and works with GCC 3.2. HTH, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
#define DEFINE_BIND_TYPE(name,expr) \ typedef boost::remove_reference< \ boost::remove_cv<typeof(expr)>::type>::type name##_expr_type; \ \ struct name:name##_expr_type \ { \ name():name##_expr_type(expr){} \ };
DEFINE_BIND_TYPE( extractor, boost::bind(&std::string::size,boost::bind(&foo::s,_1)))
typedef multi_index_container< foo, indexed_by< hashed_unique<extractor> >
mi_t;
Whether this is more convenient than writing your own key extractors is a debatable issue... One final warning: this trick relies on an undocumented feature of boost::bind, namely that the function objects produced by this lib own a result_type nested typedef, as required by the key extractor concept --otherwise the classes defined by DEFINE_BIND_TYPE wouldn't be conformant key extractors. So, if you want to stand on the documented side you couldn't use this. Also, this is one reason why thes idiom does not extend to boost::lambda expressions.
I've been playing with the problem too, and found this solution...it does not rely on typeof, but it does rely on return_type. I'm a bit unsure about why I had to use "unsigned int" to make it work, so I'd welcome some comments on this. template<class T, typename MemberType, MemberType T::* MemberPtr, typename RetType, RetType (MemberType::*MemberFct)() const> struct extract_and_call { typedef unsigned int result_type; unsigned int operator()(T const& t) const { return ((t .* MemberPtr) .* MemberFct)(); } }; typedef multi_index_container< foo, indexed_by< hashed_unique< extract_and_call<foo, std::string, &foo::s, std::string::size_type, &std::string::size> >, ordered_unique< extract_and_call<foo, std::string, &foo::s, std::string::size_type, &std::string::size> > >
mi_t;
Cheers, Filip
Filip Konvi?ka ha escrito:
I've been playing with the problem too, and found this solution...it does not rely on typeof, but it does rely on return_type. I'm a bit unsure about why I had to use "unsigned int" to make it work, so I'd welcome some comments on this.
Do you mean you couldn't use RetType properly? I've tried with the following in GCC 3.2: template<class T, typename MemberType, MemberType T::* MemberPtr, typename RetType, RetType (MemberType::*MemberFct)() const> struct extract_and_call { typedef RetType result_type; RetType operator()(T const& t) const { return ((t .* MemberPtr) .* MemberFct)(); } }; and everything seems to be working fine. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
I've been playing with the problem too, and found this solution...it does not rely on typeof, but it does rely on return_type. I'm a bit unsure about why I had to use "unsigned int" to make it work, so I'd welcome some comments on this.
Do you mean you couldn't use RetType properly? I've tried with the following in GCC 3.2:
template<class T, typename MemberType, MemberType T::* MemberPtr, typename RetType, RetType (MemberType::*MemberFct)() const> struct extract_and_call { typedef RetType result_type; RetType operator()(T const& t) const { return ((t .* MemberPtr) .* MemberFct)(); } };
Aye, I got the following warning that I could not get rid of (VC 7.1) C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : warning C4267: 'argument' : conversion from 'size_t' to 'unsigned int', possible loss of data Complete error (warning) message: C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : error C2220: warning treated as error - no object file generated C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(130) : while compiling class-template member function 'size_t boost::hash_detail::call_hash<T>::call(const T &)' with [ T=extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>::result_type ] C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(315) : see reference to class template instantiation 'boost::hash_detail::call_hash<T>' being compiled with [ T=extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>::result_type ] C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(314) : while compiling class-template member function 'size_t boost::hash<T>::operator ()(const T &) const' with [ T=extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>::result_type ] C:\Boost\include\boost-1_33_1\boost\multi_index\hashed_index.hpp(980) : see reference to class template instantiation 'boost::hash<T>' being compiled with [ T=extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,st d::char_traits<char>,std::allocator<char>>::size(void) const>::result_type ] C:\Boost\include\boost-1_33_1\boost\multi_index_container.hpp(80) : see reference to class template instantiation 'boost::multi_index::detail::hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>' being compiled with [ KeyFromValue=boost::multi_index::hashed_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>::key_from_value_type, Hash=boost::multi_index::hashed_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>::hash_type, Pred=boost::multi_index::hashed_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>::pred_type, SuperMeta=boost::multi_index::detail::nth_layer<1,foo,boost::multi_index::indexed_by<boost::multi_index::hashed_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>,boost::multi_index::ordered_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::siz e_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>>,std::allocator<foo>>, TagList=boost::multi_index::hashed_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>::tag_list_type, Category=boost::multi_index::detail::hashed_unique_tag ] LCS.cpp(94) : see reference to class template instantiation 'boost::multi_index::multi_index_container<Value,IndexSpecifierList>' being compiled with [ Value=foo, IndexSpecifierList=boost::multi_index::indexed_by<boost::multi_index::hashed_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>,boost::multi_index::ordered_unique<extract_and_call<foo,std::string,pointer-to-member(0x0),std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type,std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size_type std::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(void) const>>> ] C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : warning C4267: 'argument' : conversion from 'size_t' to 'unsigned int', possible loss of data Cheers, Filip
Filip Konvi?ka ha escrito:
I've been playing with the problem too, and found this solution...it does not rely on typeof, but it does rely on return_type. I'm a bit unsure about why I had to use "unsigned int" to make it work, so I'd welcome some comments on this.
Do you mean you couldn't use RetType properly? I've tried with the following in GCC 3.2:
template<class T, typename MemberType, MemberType T::* MemberPtr, typename RetType, RetType (MemberType::*MemberFct)() const> struct extract_and_call { typedef RetType result_type; RetType operator()(T const& t) const { return ((t .* MemberPtr) .* MemberFct)(); } };
Aye, I got the following warning that I could not get rid of (VC 7.1)
C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : warning C4267: 'argument' : conversion from 'size_t' to 'unsigned int', possible loss of data
[...] Looks like an overzealous or simply misguided warning. Can you please try the following? #include <boost/functional/hash/hash.hpp> #include <cstddef> int main() { std::size_t x=0; boost::hash<std::size_t>()(x); } Same warning? If so, you might ask for inclusion of a suitable #pragma warning(disable...) to the Boost.Hash author. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Looks like an overzealous or simply misguided warning. Can you please try the following?
#include <boost/functional/hash/hash.hpp> #include <cstddef>
int main() { std::size_t x=0; boost::hash<std::size_t>()(x); }
Same warning? If so, you might ask for inclusion of a suitable #pragma warning(disable...) to the Boost.Hash author.
Yes...in fact, boost::hash<unsigned int>()(x); works fine, since the function being called (via boost::hash and boost::call_hash) is defined as inline std::size_t hash_value(unsigned int v) { return static_cast<std::size_t>(v); } There are other variants of this function, taking bool, int, etc. as the argument, but no size_t. I'm not sure what is the official interface of boost::hash, so I don't know whether it's being used correctly in multi_index or not. Cheers, Filip
Filip Konvi?ka ha escrito:
Looks like an overzealous or simply misguided warning. Can you please try the following?
#include <boost/functional/hash/hash.hpp> #include <cstddef>
int main() { std::size_t x=0; boost::hash<std::size_t>()(x); }
Same warning? If so, you might ask for inclusion of a suitable #pragma warning(disable...) to the Boost.Hash author.
Yes...in fact,
boost::hash<unsigned int>()(x);
works fine, since the function being called (via boost::hash and boost::call_hash) is defined as
inline std::size_t hash_value(unsigned int v) { return static_cast<std::size_t>(v); }
Do you mean hash_value(unsigned int) is also invoked when using boost::hash<std::size_t>, right?
There are other variants of this function, taking bool, int, etc. as the argument, but no size_t.
This is correct, because std::size_t is a typedef to some builtin unsigned integer type.
I'm not sure what is the official interface of boost::hash, so I don't know whether it's being used correctly in multi_index or not.
I hope Boost.Hash is used correctly by Boost.MultiIndex :) but anyway the issue has little to do with the last lib since the snippet I provided in my previous post (involving only Boost.Hash) replicates the warning. Are you compiling with /Wp64 (Detect 64-Bit Portability Issues)? If so, could you please: a) look in your stdlib headers (most likely in stddef.h) how size_t is defined? b) try the following snippet and report whether the warning persists? #include <cstddef> void foo(unsigned int){} int main() { std::size_t x=0; foo(x); } Thank you! Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Do you mean hash_value(unsigned int) is also invoked when using boost::hash<std::size_t>, right?
Yes.
There are other variants of this function, taking bool, int, etc. as the argument, but no size_t.
This is correct, because std::size_t is a typedef to some builtin unsigned integer type.
Unfortunately, this is not in the case.... typedef __w64 unsigned int size_t; This is due to /Wp64, as you have correctly guessed.
a) look in your stdlib headers (most likely in stddef.h) how size_t is defined?
See above.
b) try the following snippet and report whether the warning persists?
#include <cstddef>
void foo(unsigned int){}
int main() { std::size_t x=0; foo(x); }
This exhibits the same problem. Both are fine without /Wp64. So I think that adding /Wp64 means that the warning should be turned off.
Thank you!
Thank you! Cheers, Filip
Filip Konvi?ka ha escrito: [...]
Unfortunately, this is not in the case....
typedef __w64 unsigned int size_t;
This is due to /Wp64, as you have correctly guessed.
a) look in your stdlib headers (most likely in stddef.h) how size_t is defined?
See above.
b) try the following snippet and report whether the warning persists?
#include <cstddef>
void foo(unsigned int){}
int main() { std::size_t x=0; foo(x); }
This exhibits the same problem. Both are fine without /Wp64. So I think that adding /Wp64 means that the warning should be turned off.
Well, /Wp64 is useful, but only for simple cases: once static polymorphism enters the scene (function overloads, template metaprogramming...) it is easy to unwantedly fool this option. You might want to try to convince the Boost.Hash author to take care of this by guarding the relevant code inside the lib with #pragma warning(push) #pragma warning(disable:4312 4311) ... #pragma warning(pop) when appropriate (i.e. only for VC++ 7.1 (and 8.0?) etc.); or better yet, you can try to do the modifications yourself and propose the resulting patch here at the list. Best regards, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Joaquín Mª López Muñoz ha escrito: [...]
You might want to try to convince the Boost.Hash author to take care of this by guarding the relevant code inside the lib with
#pragma warning(push) #pragma warning(disable:4312 4311)
I mean #pragma warning(disable:4267) Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Joaquín Mª López Muñoz wrote:
Filip Konvi?ka ha escrito:
Aye, I got the following warning that I could not get rid of (VC 7.1)
C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : warning C4267: 'argument' : conversion from 'size_t' to 'unsigned int', possible loss of data
[...]
Looks like an overzealous or simply misguided warning. Can you please try the following?
[...]
Same warning? If so, you might ask for inclusion of a suitable #pragma warning(disable...) to the Boost.Hash author.
Depending on your concern for portability, you might not want to dismiss this warning. VC 7.1 and 8.0 provide it as part of their 64 bit portability warnings (size_t will be 64 bits wide on 64-bit Windows, while unsigned int will remain 32 bits). A better way to eliminate the warning might be to switch off the 64 bit portability warnings in your project options.
I wrote:
Depending on your concern for portability, you might not want to dismiss this warning. VC 7.1 and 8.0 provide it as part of their 64 bit portability warnings (size_t will be 64 bits wide on 64-bit Windows, while unsigned int will remain 32 bits). A better way to eliminate the warning might be to switch off the 64 bit portability warnings in your project options.
And I see my email client didn't bother to put the rest of this conversation in the same thread. Sorry about the extra noise.
Hello Andrew, Andrew Holden ha escrito:
Joaquín Mª López Muñoz wrote:
Filip Konvi?ka ha escrito:
Aye, I got the following warning that I could not get rid of (VC 7.1)
C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : warning C4267: 'argument' : conversion from 'size_t' to 'unsigned int', possible loss of data
[...]
Looks like an overzealous or simply misguided warning. Can you please try the following?
[...]
Same warning? If so, you might ask for inclusion of a suitable #pragma warning(disable...) to the Boost.Hash author.
Depending on your concern for portability, you might not want to dismiss this warning. VC 7.1 and 8.0 provide it as part of their 64 bit portability warnings (size_t will be 64 bits wide on 64-bit Windows, while unsigned int will remain 32 bits). A better way to eliminate the warning might be to switch off the 64 bit portability warnings in your project options.
I'm not advocating that the warning be completely disabled, but only in a selective manner inside Boost.Hash code by using #pragma warning(push) and #pragma warning(pop): // boost/hash/hash.hpp #pragma warning(push) #pragma warning(disable:4267) ... #pragma warning(pop) Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
On 3/16/07, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
Hello Andrew,
Andrew Holden ha escrito:
Joaquín Mª López Muñoz wrote:
Filip Konvi?ka ha escrito:
Aye, I got the following warning that I could not get rid of (VC 7.1)
C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : warning C4267: 'argument' : conversion from 'size_t' to 'unsigned int', possible loss of data
[...]
Looks like an overzealous or simply misguided warning. Can you please try the following?
[...]
Same warning? If so, you might ask for inclusion of a suitable #pragma warning(disable...) to the Boost.Hash author.
Depending on your concern for portability, you might not want to dismiss this warning. VC 7.1 and 8.0 provide it as part of their 64 bit portability warnings (size_t will be 64 bits wide on 64-bit Windows, while unsigned int will remain 32 bits). A better way to eliminate the warning might be to switch off the 64 bit portability warnings in your project options.
I'm not advocating that the warning be completely disabled, but only in a selective manner inside Boost.Hash code by using #pragma warning(push) and #pragma warning(pop):
// boost/hash/hash.hpp #pragma warning(push) #pragma warning(disable:4267) ... #pragma warning(pop)
Maybe it would be better if boost::hash included a size_t version: inline std::size_t hash_value(std::size_t v) { return v; } If necessary, in cases where std::size_t == unsigned int, it could probably use is_same<T,U> to make sure both versions didn't exist and cause warnings/errors. Tony
Gottlob Frege ha escrito:
On 3/16/07, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
Hello Andrew,
Andrew Holden ha escrito:
Joaquín Mª López Muñoz wrote:
Filip Konvi?ka ha escrito:
Aye, I got the following warning that I could not get rid of (VC 7.1)
C:\Boost\include\boost-1_33_1\boost\functional\hash\hash.hpp(132) : warning C4267: 'argument' : conversion from 'size_t' to 'unsigned int', possible loss of data
[...]
Looks like an overzealous or simply misguided warning. Can you please try the following?
[...]
Same warning? If so, you might ask for inclusion of a suitable #pragma warning(disable...) to the Boost.Hash author.
Depending on your concern for portability, you might not want to dismiss this warning. VC 7.1 and 8.0 provide it as part of their 64 bit portability warnings (size_t will be 64 bits wide on 64-bit Windows, while unsigned int will remain 32 bits). A better way to eliminate the warning might be to switch off the 64 bit portability warnings in your project options.
I'm not advocating that the warning be completely disabled, but only in a selective manner inside Boost.Hash code by using #pragma warning(push) and #pragma warning(pop):
// boost/hash/hash.hpp #pragma warning(push) #pragma warning(disable:4267) ... #pragma warning(pop)
Maybe it would be better if boost::hash included a size_t version:
inline std::size_t hash_value(std::size_t v) { return v; }
If necessary, in cases where std::size_t == unsigned int, it could probably use is_same<T,U> to make sure both versions didn't exist and cause warnings/errors.
Hello Tony, this does not work, as VC 8.0 (and I guess VC 7.1 too) treats (in 32 bit) std::size_t and unsigned int as the very same type except for /Wp64 diagnosis purposes. AFAICS you cannot even distinguish std::size_t from unsigned int with any template machinery, however smart --which is fine after all, since the standard mandates that std::size_t be a typedef of one of the fundamental integer types, thus ruling out the posibility that std::size_t is its own separate type. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
On Tue, 20 Mar 2007 17:54:53 -0000, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
Maybe it would be better if boost::hash included a size_t version:
inline std::size_t hash_value(std::size_t v) { return v; }
If necessary, in cases where std::size_t == unsigned int, it could probably use is_same<T,U> to make sure both versions didn't exist and cause warnings/errors.
Sorry, I didn't notice this thread before. This has actually been fixed in 1.34, and 1.35 will have proper suport for 'long long' and 'unsigned long long'. If you can't upgrade when 1.34 is released (which should be soon?), I'd suggest that you add this function to the boost namespace, either in or before the boost headers. It's a pretty nasty hack but the warning is valid so it's worth it. Daniel
On Tue, 20 Mar 2007 17:54:53 -0000, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
Maybe it would be better if boost::hash included a size_t version:
inline std::size_t hash_value(std::size_t v) { return v; }
If necessary, in cases where std::size_t == unsigned int, it could probably use is_same<T,U> to make sure both versions didn't exist and cause warnings/errors.
Sorry, I didn't notice this thread before. This has actually been fixed in 1.34, and 1.35 will have proper suport for 'long long' and 'unsigned long long'. If you can't upgrade when 1.34 is released (which should be soon?), I'd suggest that you add this function to the boost namespace, either in or before the boost headers. It's a pretty nasty hack but the warning is valid so it's worth it.
Great, thanks for the info! I was rather reluctant about disabling that warning. Looking forward to 1.34 :-) Cheers, Filip
On Thu, 22 Mar 2007 09:22:57 -0000, Filip Konvička <filip.konvicka@logis.cz> wrote:
Sorry, I didn't notice this thread before. This has actually been fixed in 1.34, and 1.35 will have proper suport for 'long long' and 'unsigned long long'. If you can't upgrade when 1.34 is released (which should be soon?), I'd suggest that you add this function to the boost namespace, either in or before the boost headers. It's a pretty nasty hack but the warning is valid so it's worth it.
Great, thanks for the info! I was rather reluctant about disabling that warning. Looking forward to 1.34 :-)
Sorry, if you didn't catch it from my reply to Joaquin, I was wrong. The 1.34 code does work on 64-bit Windows but the warning will is still there on 32 bit machines. I was foolish enough to only support 64-bit machines on 64-bit machines. Unfortunately, it's too late to fix it. Daniel
Daniel James ha escrito:
On Tue, 20 Mar 2007 17:54:53 -0000, JoaquÃn Mª López Muñoz <joaquin@tid.es> wrote:
Maybe it would be better if boost::hash included a size_t version:
inline std::size_t hash_value(std::size_t v) { return v; }
If necessary, in cases where std::size_t == unsigned int, it could probably use is_same<T,U> to make sure both versions didn't exist and cause warnings/errors.
Sorry, I didn't notice this thread before. This has actually been fixed in 1.34, and 1.35 will have proper suport for 'long long' and 'unsigned long long'. If you can't upgrade when 1.34 is released (which should be soon?), I'd suggest that you add this function to the boost namespace, either in or before the boost headers. It's a pretty nasty hack but the warning is valid so it's worth it.
Hello Daniel, I think you are misunderstanding the problem.: the warning is *not* valid because it happens in 32 bit mode, where std::size_t is a typedef for unsigned int (no longs involved). Please try the following in MSVC 7.1/8.0 in 32 bit mode with /Wp64 compiler option on: #include <boost/functional/hash/hash.hpp> #include <cstddef> int main() { std::size_t x=0; boost::hash<std::size_t>()(x); } If I'm not wrong, you'll get the warning even if using Boost 1.34. The problem is that /Wp64 mode is too smart (or too dumb if you want) and sees a potential problem in casting a std::size_t to an unsigned int (which are the same in 32bit mode) because that cast would pose problems in 64 bit mode. IMHO the right course of action is to not provide overloads for size_t, provide thenm for long and long long types, so guaranteeing that size_t will be covered by some overload either in 32 or 64 bit mode, and then disabling the warning with a // boost/hash/hash.hpp #pragma warning(push) #pragma warning(disable:4267) ... #pragma warning(pop) because even if you've got everything covered /Wp64 won't be able to see it. A good thing about the proposed pragma solution is that by using push/pop facilities you eliminate the warnings inside Boost.Hash without imposing a global warning disabling to the user. HTH, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
On 3/22/07, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
Hello Daniel, I think you are misunderstanding the problem.: the warning is *not* valid because it happens in 32 bit mode, where std::size_t is a typedef for unsigned int (no longs involved).
The warning only ever happens in 32bit mode - it warns about what *would* happen if compiled in 64 bit mode. So the warning, in general, is valid.
The problem is that /Wp64 mode is too smart (or too dumb if you want) and sees a potential problem in casting a std::size_t to an unsigned int (which are the same in 32bit mode) because that cast would pose problems in 64 bit mode. IMHO the right course of action is to not provide overloads for size_t, provide thenm for long and long long types, so guaranteeing that size_t will be covered by some overload either in 32 or 64 bit mode, and then disabling the warning with a
// boost/hash/hash.hpp #pragma warning(push) #pragma warning(disable:4267) ... #pragma warning(pop)
because even if you've got everything covered /Wp64 won't be able to see it. A good thing about the proposed pragma solution is that by using push/pop facilities you eliminate the warnings inside Boost.Hash without imposing a global warning disabling to the user.
That sounds exactly right. In this case the warning is NOT valid because you've covered all sizes via the various overloads, but the warning can't see that. So use pragmas to shut it off - but make sure the pragmas are as close as possible to the code in question. Alternatively, since size_t is guaranteed to be the same as some integer, you could make sure there is a size_t version, and only do an int or long version if they are NOT size_t. But that seems hokey just to avoid a warning.
HTH,
Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Tony
On Thu, 22 Mar 2007 09:32:37 -0000, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
Hello Daniel, I think you are misunderstanding the problem.: the warning is *not* valid because it happens in 32 bit mode, where std::size_t is a typedef for unsigned int (no longs involved).
Sorry, you're right, I missed the context and thought he was compiling in 64 bit mode.
IMHO the right course of action is to not provide overloads for size_t, provide thenm for long and long long types, so guaranteeing that size_t will be covered by some overload either in 32 or 64 bit mode
I actually do this. 1.35 will have full long long support on any compiler which supports it, mixing up the value if sizeof(std::size_t) < sizeof(unsigned long long) - which is often true. I didn't put it into 1.34 because we had branched for release (in theory) and it was a new feature - so instead I have a simpler implementation just for 64-bit windows.
and then disabling the warning with a
// boost/hash/hash.hpp #pragma warning(push) #pragma warning(disable:4267) ... #pragma warning(pop)
because even if you've got everything covered /Wp64 won't be able to see it.
That would be the right thing to do, but I don't think avoiding a warning is important enough to break the code freeze. Sorry. If there's a 1.34.1 it'll be in it. Daniel
participants (6)
-
Andrew Holden
-
Boris
-
Daniel James
-
Filip Konvička
-
Gottlob Frege
-
Joaquín Mª López Muñoz