std :: vector класса с частным конструктором не компилируется при использовании современных С++
Код, над которым я работаю, изначально был разработан с использованием C++03
и компилируется и функционирует без ошибок с использованием g++ -std=c++03
. Моя цель состоит в том, чтобы скомпилировать тот же код с помощью g++ -std=c++17
.
Код содержит MyClass
который содержит NestedClass
. Только MyClass
должен иметь возможность использовать, создавать и изменять экземпляры NestedClass
, которые хранятся в std::vector< NestedClass >
. Таким образом, NestedClass
содержит частный конструктор и объявляет MyClass
и std::vector< NestedClass >
качестве друзей.
Минимальный пример:
#include <vector>
class MyClass {
public:
class NestedClass {
friend class MyClass;
friend class std::vector< NestedClass >;
double _d;
NestedClass( double d = 0.0 ) : _d(d){ }
};
private:
std::vector< NestedClass > data;
public:
MyClass(){
data.resize( 40 );
}
};
int main(){
MyClass myclass = MyClass();
return 0;
}
Этот минимальный пример не выполняется при компиляции -std=c++17
со следующей ошибкой:
/usr/include/c++/7/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = MyClass::NestedClass; _Args = {}]:
/usr/include/c++/7/bits/stl_uninitialized.h:527:18: required from ‘static _ForwardIterator std::__uninitialized_default_n_1<_TrivialValueType>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = MyClass::NestedClass*; _Size = long unsigned int; bool _TrivialValueType = false]
/usr/include/c++/7/bits/stl_uninitialized.h:583:20: required from ‘_ForwardIterator std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator = MyClass::NestedClass*; _Size = long unsigned int]
/usr/include/c++/7/bits/stl_uninitialized.h:645:44: required from ‘_ForwardIterator std::__uninitialized_default_n_a(_ForwardIterator, _Size, std::allocator<_Tp>&) [with _ForwardIterator = MyClass::NestedClass*; _Size = long unsigned int; _Tp = MyClass::NestedClass]
/usr/include/c++/7/bits/vector.tcc:563:35: required from ‘void std::vector<_Tp, _Alloc>::_M_default_append(std::vector<_Tp, _Alloc>::size_type) [with _Tp = MyClass::NestedClass; _Alloc = std::allocator<MyClass::NestedClass>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]
/usr/include/c++/7/bits/stl_vector.h:692:21: required from ‘void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = MyClass::NestedClass; _Alloc = std::allocator<MyClass::NestedClass>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]
bug.cpp:21:20: required from here
/usr/include/c++/7/bits/stl_construct.h:75:7: error: ‘MyClass::NestedClass::NestedClass(double) is private within this context
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bug.cpp:11:4: note: declared private here
NestedClass( double d = 0.0 ) : _d(d){ }
Как я могу переписать код так, чтобы он компилировался с использованием С++ 17?
Изменение std::vector< NestedClass >
на std::vector< NestedClass * >
не является вариантом, поскольку для этого потребуется переписать код, который использует MyClass
который я не контролирую.
Ответы
Ответ 1
Минимальное исправление для вашего конкретного примера
data.resize( 40, {} );
Вызовите частного конструктора самостоятельно, так что vector
нужно только вызвать (неявно объявленные) публичные.
В общем, подружиться с чем-то в библиотеке, которую вы не контролируете, не работает. Вы понятия не имеете, сказал ли кто-нибудь что-то на деле, чтобы делегировать работу на что-то еще.
В vector
случае в значительной степени требуется делегировать указанную работу чему-то еще.
Правильное исправление, вероятно, будет связано с изменениями в соответствующих классах. Одна из возможностей - идиома passkey: сделать конструкторы общедоступными, но только вызываемыми с аргументом частного типа.