Я застрял в течение нескольких часов, пытаясь понять, почему следующий код не компилируется, и был бы признателен, если бы кто-нибудь мог указать, что мне не хватает.
Код - это просто упрощенный пример проблемы с компиляцией, с которой я сталкиваюсь в реальном коде проекта.
#include <map>
#include <string>
#include <utility>
class A
{
public:
A() = default;
A(const A& v) = default;
A(A&& v) = default;
A& operator=(const A& v) = default;
A& operator=(const std::pair<A, A>& v)
{
return *this;
}
};
void func(const std::pair<int, A>& obj);
int main(int argc, char *argv[])
{
std::pair<int, A> obj;
func(obj);
return 0;
}
void func(const std::pair<int, A>& obj)
{
A a, b;
a = b;
}
Проблема, похоже, связана с «A& operator=(const std::pair<A, A>& v)». Что меня смущает, так это то, что если я перемещаю функцию "void func(...)" перед main(), все компилируется правильно.
Скомпилировано с помощью gcc (C++17). Ошибка, которую я получаю, выглядит так:
In file included from /usr/include/c++/7/bits/move.h:54:0,
from /usr/include/c++/7/bits/stl_pair.h:59,
from /usr/include/c++/7/bits/stl_algobase.h:64,
from /usr/include/c++/7/bits/stl_tree.h:63,
from /usr/include/c++/7/map:60,
from main.cpp:1:
/usr/include/c++/7/type_traits: In instantiation of ‘struct std::__and_<std::is_copy_assignable<A>, std::is_copy_assignable<A> >’:
/usr/include/c++/7/bits/stl_pair.h:378:7: required from ‘struct std::pair<A, A>’
/usr/include/c++/7/type_traits:1259:45: required by substitution of ‘template<class _Tp1, class _Up1, class> static std::true_type std::__is_assignable_helper<A&, const A&>::__test<_Tp1, _Up1, <template-parameter-1-3> >(int) [with _Tp1 = A&; _Up1 = const A&; <template-parameter-1-3> = <missing>]’
/usr/include/c++/7/type_traits:1268:40: required from ‘class std::__is_assignable_helper<A&, const A&>’
/usr/include/c++/7/type_traits:1273:12: required from ‘struct std::is_assignable<A&, const A&>’
/usr/include/c++/7/type_traits:1285:12: required from ‘struct std::__is_copy_assignable_impl<A, true>’
/usr/include/c++/7/type_traits:1291:12: required from ‘struct std::is_copy_assignable<A>’
/usr/include/c++/7/type_traits:143:12: required from ‘struct std::__and_<std::is_copy_assignable<int>, std::is_copy_assignable<A> >’
/usr/include/c++/7/bits/stl_pair.h:378:7: required from ‘struct std::pair<int, A>’
<span class = "error_line" onclick = "ide.gotoLine('main.cpp',23)">main.cpp:23:20</span>: required from here
/usr/include/c++/7/type_traits:143:12: error: incomplete type ‘std::is_copy_assignable’ used in nested name specifier
struct __and_<_B1, _B2>
^~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:64:0,
from /usr/include/c++/7/bits/stl_tree.h:63,
from /usr/include/c++/7/map:60,
from main.cpp:1:
/usr/include/c++/7/bits/stl_pair.h: In instantiation of ‘struct std::pair<A, A>’:
/usr/include/c++/7/type_traits:1259:45: required by substitution of ‘template<class _Tp1, class _Up1, class> static std::true_type std::__is_assignable_helper<A&, const A&>::__test<_Tp1, _Up1, <template-parameter-1-3> >(int) [with _Tp1 = A&; _Up1 = const A&; <template-parameter-1-3> = <missing>]’
/usr/include/c++/7/type_traits:1268:40: required from ‘class std::__is_assignable_helper<A&, const A&>’
/usr/include/c++/7/type_traits:1273:12: required from ‘struct std::is_assignable<A&, const A&>’
/usr/include/c++/7/type_traits:1285:12: required from ‘struct std::__is_copy_assignable_impl<A, true>’
/usr/include/c++/7/type_traits:1291:12: required from ‘struct std::is_copy_assignable<A>’
/usr/include/c++/7/type_traits:143:12: required from ‘struct std::__and_<std::is_copy_assignable<int>, std::is_copy_assignable<A> >’
/usr/include/c++/7/bits/stl_pair.h:378:7: required from ‘struct std::pair<int, A>’
<span class = "error_line" onclick = "ide.gotoLine('main.cpp',23)">main.cpp:23:20</span>: required from here
/usr/include/c++/7/bits/stl_pair.h:378:7: error: ‘value’ is not a member of ‘std::__and_, std::is_copy_assignable >’
operator=(typename conditional<
^~~~~~~~





То, что вы испытываете сейчас, является ярким примером неопределенного поведения, поскольку реализация std::pair зависит от type_traits, которые не определены для неполных типов.
Внутри области действия A, но вне каких-либо функций-членов A считается неполным типом. Вы пытаетесь определить функцию, которая принимает std::pair<A, A> и, таким образом, создаете экземпляр std::pair с неполным типом.
Это не тот случай, если бы A был шаблонным типом, поскольку функции шаблонов классов не создаются до тех пор, пока они не будут фактически вызваны.
Не совсем. Вы все еще объявляете std::pair<A, A> в рамках A. Проще всего, вероятно, определить свободную функцию для выполнения присваивания.
Я понимаю. C++ не перестает меня удивлять.
Было бы правильным решением принудительно создать экземпляр шаблона, добавив эту строку после класса? "класс шаблона std::pair<A, A>;"
Нет, это уже слишком поздно. Вы уже создали его, когда A был еще незавершенным.
Итак, проблема будет решена путем перемещения определения
operator=за пределы класса?