Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X3: MSVC unordered containers is_reservable<T>::value == false #298

Closed
octopus-prime opened this issue Nov 27, 2017 · 9 comments
Closed
Labels

Comments

@octopus-prime
Copy link
Collaborator

octopus-prime commented Nov 27, 2017

Until we have a good integration for boostorg/spirit in appveyor - this is what we get for now (via private appveyor account):

compile-c-c++ bin.v2\libs\spirit\test\x3\x3_container_support-p3.test\msvc-14.1\release\address-model-64\threadapi-win32\threading-multi\container_support.obj
container_support.cpp
libs\spirit\test\x3\container_support.cpp(181): error C2338: is_reservable problem
libs\spirit\test\x3\container_support.cpp(183): error C2338: is_reservable problem
libs\spirit\test\x3\container_support.cpp(185): error C2338: is_reservable problem
libs\spirit\test\x3\container_support.cpp(187): error C2338: is_reservable problem

https://ci.appveyor.com/project/octopus-prime/spirit

@octopus-prime
Copy link
Collaborator Author

octopus-prime commented Nov 27, 2017

The errors came from reservable-tests of std::unordered_xyz classes.

So this is the standard
http://en.cppreference.com/w/cpp/container/unordered_map
with reserve()

And this is boost
http://www.boost.org/doc/libs/1_65_1/doc/html/boost/unordered_map.html
with reserve()

But (of course) this is microsoft
https://msdn.microsoft.com/de-de/library/bb982522.aspx
WITHOUT reserve() 👎

@Kojoley Kojoley changed the title build errors in appveyor for x3 container_support.cpp X3: MSVC unordered containers miss reserve Nov 28, 2017
@Kojoley Kojoley changed the title X3: MSVC unordered containers miss reserve X3: MSVC unordered containers is_reservable<T>::value == false Nov 28, 2017
@Kojoley
Copy link
Collaborator

Kojoley commented Nov 28, 2017

This perfectly compiles on VS 2015, 2017:

#include <unordered_map>
#include <unordered_set>

int main()
{
    std::unordered_map<int, int> umap;
    umap.reserve(1);

    std::unordered_set<int> uset;
    uset.reserve(1);

    std::unordered_multimap<int, int> ummap;
    ummap.reserve(1);

    std::unordered_multiset<int> umset;
    umset.reserve(1);

    return 0;
}

It should be a problem in traits.

@octopus-prime
Copy link
Collaborator Author

octopus-prime commented Nov 28, 2017

Would like to find the difference.
I don't have MSVC - so can not try to find it.
Can only read documentation to find the difference in reserve method.
But documentation says: no reserve method.

https://msdn.microsoft.com/en-us/library/bb982522.aspx

@Kojoley
Copy link
Collaborator

Kojoley commented Nov 28, 2017

Here is the problem:

MSVC unordered containers have a base _Hash from which reserve member comes from:

	class unordered_map
		: public _Hash<_Umap_traits<_Kty, _Ty,
			_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>>

but BOOST_TTI_HAS_MEMBER_FUNCTION cannot introspect for inherited members https://groups.google.com/forum/#!topic/boost-list/awd4kqJezfQ

#include <boost/tti/has_member_function.hpp>
#include <iostream>

BOOST_TTI_HAS_MEMBER_FUNCTION(function1);

struct A { int function1(); };
struct B : A {};

int main()
{
    std::cout << std::boolalpha
        << has_member_function_function1<A, int>::value << std::endl // 1. true
        << has_member_function_function1<B, int>::value << std::endl // 2. false
        ;
    return 0;
}

@octopus-prime
Copy link
Collaborator Author

Excellent analysis!

@octopus-prime
Copy link
Collaborator Author

octopus-prime commented Nov 29, 2017

Possible solution:

#include <iostream>

struct A {
  void reserve(size_t);
};
struct B : A {};

// For this approach we need a void_t
// We could use std::void_t (but it's c++17)
// Is there something equivalent in boost?!
// If not we can define it by:
template <typename... T> using void_t = void;

template <typename T, typename = void>
struct has_reserve : std::false_type {};

template <typename T>
struct has_reserve<T, void_t<
    decltype(std::declval<T&>().reserve(size_t{}))
>> : std::true_type {};

template <typename T, typename = void>
struct has_foo : std::false_type {};

template <typename T>
struct has_foo<T, void_t<
    decltype(std::declval<T&>().foo(size_t{}))
>> : std::true_type {};

int main() {
  std::cout << std::boolalpha
            << has_reserve<A>::value << std::endl // true
            << has_reserve<B>::value << std::endl // true
            << has_foo<A>::value << std::endl     // false
            << has_foo<B>::value << std::endl     // false
      ;
  return 0;
}

Can somebody check whether this code works with MSVC?

@MarcelRaad
Copy link
Contributor

@octopus-prime Works fine with MSVC 14.11 (2017 Update 3+).

@Kojoley
Copy link
Collaborator

Kojoley commented Nov 29, 2017

It should, because it looks like that one I has
45902cb

@octopus-prime
Copy link
Collaborator Author

@Kojoley Really nice job!! Without void_t at all...

Kojoley pushed a commit that referenced this issue Dec 16, 2017
- Fixes #298 and is based on 45902cb provided by @Kojoley 
- Added container_support.cpp to x3 test suite again
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants