boostorg / multi_index

Boost.org multi_index module
http://boost.org/libs/multi_index
45 stars 59 forks source link

C2039: 'is_first_of_group': is not a member of 'boost::multi_index::detail::hashed_index_node_alg #59

Closed playgithub closed 2 years ago

playgithub commented 2 years ago

Env

Windows Visual Studio 2022 boost 1.78.0 vcpkg C++ 17

Compile Error

C2039: 'is_first_of_group': is not a member of 'boost::multi_index::detail::hashed_index_node_alg

Source Code

https://github.com/boostorg/multi_index/blob/9c40dfee82e3c42960e137cd765d7bcb850dc256/include/boost/multi_index/hashed_index.hpp#L1598

joaquintides commented 2 years ago

Hi, thanks for the report. I'd need more info to be able to reproduce the error, as tests here for VS 2022 run OK (look for "msvc- 14.3" at https://www.boost.org/development/tests/master/developer/multi_index.html).

Thank you,

playgithub commented 2 years ago

Hi, thanks for the report. I'd need more info to be able to reproduce the error, as tests here for VS 2022 run OK (look for "msvc- 14.3" at https://www.boost.org/development/tests/master/developer/multi_index.html).

  • Can you provide more info on the environment where you've found the problem?

Strangely, in Visual Studio 2022 solution which also use vcpkg, it builds successfully.

  • Can you provide a link to the code using Boost.MultiIndex that triggered the compiler error? Even better, can you provide a minimal, complete and verifiable example code showing the problem?

I've written a simple project, but it can't be reproduced, it builds successfully.

It might be a bug for me, so close the issue first, if it is for me, I should reopen it with enough info.

Thanks

joaquintides commented 2 years ago

Ok, good luck with your project.

joaquintides commented 2 years ago

Hi Ronald

I received a notification of some additional comment of yours on this issue, but the comment is not appearing online now, maybe you've deleted it?

playgithub commented 2 years ago

I received a notification of some additional comment of yours on this issue, but the comment is not appearing online now, maybe you've deleted it?

Yes, when using it with

it doesn't work, but when using it with

it works

So I'm not sure what's the problem.

I'm going to test the former case on Linux.

joaquintides commented 2 years ago

In a comment that didn't make it online (yet I received via a notification email) you talked about a sample.cpp file. Would it be possible to take a look at that?

playgithub commented 2 years ago

In a comment that didn't make it online (yet I received via a notification email) you talked about a sample.cpp file. Would it be possible to take a look at that?

sample.cpp is just a placeholder , I've tried to write a simple demo, but it can't be reproduced. BTW, I've tried linux, but it got another problems when do conan install for boost. Anyway I'm going to debug it on Windows. If I find s.th. helpful, I'll post it here.

playgithub commented 2 years ago

The problem is caused by __declspec(dllexport), if comment it out, there will be no problem. Anyway to export a class derived from bmi::multi_index_container on Windows?

#include <memory>
#include <string>

#include <boost/uuid/uuid.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/mem_fun.hpp>

namespace bmi = boost::multi_index;

class A
{
public:
    A(int id, const std::string& name) : __id(id), __name(name) {}
public:
    int GetID() const { return __id; }
    const std::string& GetName() const { return __name; }
private:
    int __id;
    std::string __name;
};

struct random_access_index_tag;
struct id_index_tag;
struct name_index_tag;

typedef bmi::multi_index_container<
    std::shared_ptr<A>,
    bmi::indexed_by<
    bmi::random_access<bmi::tag<random_access_index_tag>>,
    bmi::hashed_unique<bmi::tag<id_index_tag>, bmi::const_mem_fun<A, int, &A::GetID>>,
    bmi::hashed_unique<bmi::tag<name_index_tag>, bmi::const_mem_fun<A, const std::string&, &A::GetName>>
    >
> AMultiIndexContainer;

class __declspec(dllexport) AGroup : public AMultiIndexContainer
{
};
playgithub commented 2 years ago

In the post https://stackoverflow.com/a/7302165, it says "C++ is not a "pure OOP" and container are not OOP at all.". Does it mean that in this case it is not well supported to derive from boost::multi_index?

joaquintides commented 2 years ago

Your problem has nothing to do with deriving from multi_index_container (which some may find questionable but is undoubtedly doable). What I think it's happening is the following:

playgithub commented 2 years ago

So the problem dues to the functions below when exporting

bool in_place(
    node_impl_pointer x,key_param_type k,std::size_t buc,
    hashed_unique_tag)const
  bool in_place(
    node_impl_pointer x,key_param_type k,std::size_t buc,
    hashed_non_unique_tag)const

But the compiler is exporting and, consequently, trying to compile both, and the non-unique version fails because, well, the index is unique.

I don't quite understand this, does it mean they have the same function signature to the complier, and only one can be exported when exporting? And for static link, it simply works by specializing the template with different template param Category, right?

joaquintides commented 2 years ago

It doesn't have to do with the signature, these two are different functions and the problem is that the compiler tries to generate both. Let me explain by way of an example:

template<typename T>
struct AClassTemplate
{
  static void call_foo(){T::foo();}
  static void call_bar(){T::bar();}
};

struct FooClass
{
  static void foo(){}
};

struct __declspec(dllexport) DerivedClass:AClassTemplate<FooClass>
{
  void call_foo(){AClassTemplate<FooClass>::call_foo();}
};

int main(){}

This fails because the compiler is trying to export (and compile) AClassTemplate<FooClass>::call_foo (OK) and AClassTemplate<FooClass>::call_bar (NOK, FooClass has no barmember function to call). On the contrary, the following:

template<typename T>
struct AClassTemplate
{
  static void call_foo(){T::foo();}
  static void call_bar(){T::bar();}
};

struct FooClass
{
  static void foo(){}
};

struct DerivedClass:AClassTemplate<FooClass>
{
  void __declspec(dllexport) call_foo(){AClassTemplate<FooClass>::call_foo();}
};

int main(){}

works because we are not compiling every member function of AClassTemplate<FooClass>, but only those used by the exported function DerivedClass::call_foo. Clearer now?

playgithub commented 2 years ago

Yes, clear now, because specialization of a template is not complete. Thanks very much