У меня есть следующие файлы:
"декларация.hpp"
namespace ns {
class Derived;
using DerivedPtr = std::unique_ptr<Derived>;
}
"База.hpp"
namespace ns {
class User;
class Base
{
public:
uint64_t foo() const;
};
}
"Производный.hpp"
namespace ns {
class Derived : public Base
{
public:
uint64_t bar() const;
};
}
"Пользователь.hpp"
#include "declaration.hpp"
namespace ns {
class User
{
private:
std::map<uint64_t, DerivedPtr> map;
};
}
Я попытался изменить карту в User
, чтобы она стала мультииндексной, т. е. в «declaration.hpp» я поставил
struct Foo{};
struct Bar{};
using Map = boost::multi_index_container<
DerivedPtr,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<boost::multi_index::tag<Foo>,
boost::multi_index::const_mem_fun<Base, uint64_t, &Base::foo> >,
boost::multi_index::ordered_non_unique<boost::multi_index::tag<Bar>,
boost::multi_index::const_mem_fun<Derived, uint64_t, &Derived::bar> > > >;
и
#include "declaration.hpp"
namespace ns {
class User
{
private:
Map map;
};
}
но я получаю error: incomplete type 'ns::Derived' named in nested name specifier
.
Я не могу поставить #include "Derived.hpp"
и #include "Base.hpp"
в «declaration.hpp»
потому что тогда я получаю error: member access into incomplete type
из-за предварительного объявления в «Base.hpp».
Есть ли способ добиться того, что я пытаюсь сделать? Можно ли использовать фиксированные значения для индексов, устраняя тем самым необходимость в функциях-членах?
Где в "Derived.hpp"
находится #include "Base.hpp"
? Почему у вас есть class User;
в Base.hpp
?
Derived.hpp
не было включено, и вам нужен набор буст-заголовков.
Это работает:
Файл ./Base.cpp
#include "Base.hpp"
namespace ns {
uint64_t Base::foo() const { return 9; }
} // namespace ns
Файл ./Base.hpp
#pragma once
#include <cstdint>
namespace ns {
class User;
class Base {
public:
uint64_t foo() const;
};
} // namespace ns
Файл ./Derived.cpp
#include "Derived.hpp"
namespace ns {
uint64_t Derived::bar() const { return 42; }
} // namespace ns
Файл ./Derived.hpp
#pragma once
#include "Base.hpp"
namespace ns {
class Derived : public Base {
public:
uint64_t bar() const;
};
} // namespace ns
Файл ./User.cpp
#include "User.hpp"
namespace ns {
void User::do_something() {
map.emplace(std::make_unique<Derived>());
map.emplace(std::make_unique<Derived>());
}
} // namespace ns
Файл ./User.hpp
#include "Derived.hpp"
#include "declaration.hpp"
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index_container.hpp>
// #include <map>
namespace ns {
namespace bmi = boost::multi_index;
using Map = boost::multi_index_container<
DerivedPtr,
bmi::indexed_by<bmi::ordered_unique<bmi::tag<struct Foo>, //
bmi::const_mem_fun<Base, uint64_t, &Base::foo>>, //
bmi::ordered_non_unique<bmi::tag<struct Bar>, //
bmi::const_mem_fun<Derived, uint64_t, &Derived::bar>> //
>>;
class User {
public:
void do_something();
private:
// std::map<uint64_t, DerivedPtr> map;
Map map;
};
} // namespace ns
Файл main.cpp
#include "User.hpp"
int main() {
ns::User user;
user.do_something();
};
using Map = boost::multi_index_container<
DerivedPtr,
bmi::indexed_by<bmi::ordered_unique<bmi::tag<struct Foo>, bmi::key<&Base::foo>>,
bmi::ordered_non_unique<bmi::tag<struct Bar>, bmi::key<&Derived::bar>>>>;
Пришлось немного поработать, но вот оно работает Live On Compiler Explorer
В качестве бонуса, начиная с C++17, экстракторы ключей индексирования можно значительно упростить: godbolt.org/z/8saWsxKWv
CMake работающая версия на godbolt: godbolt.org/z/eT7Yjvdxs
Приветствую @MarekR. Является ли «the_executable» специальным именем или Godbolt каким-то образом угадывает цель CMake для выполнения? [Возможно, «Программа возвращена: 0» просто сбивает с толку печать кода завершения процесса сборки]
это определено в CMakeLists.txt
. CMake может иметь несколько целей, и это подсказывает, какую из них следует запустить. Если вы нажмете «шаблоны/CMake», он также будет использовать the_executable
.
Я не знаю точно, но предполагаю, что фраза
&Derived::bar
— ваша главная проблема, если Derived не полностью определена. Можно ли написать тип оболочки для boost::multi_index::const_mem_fun<Derived, uint64_t, &Derived::bar>, который можно было бы экстернировать и получить позже?