С шаблонами: оператор разрешается первым или преобразование разрешается первым? - PullRequest
2 голосов
/ 28 апреля 2011

Вчера я видел интересное поведение компилятора и думаю, что понимаю, почему это происходит, но хочу быть уверенным.Итак, я не собираюсь писать свои рассуждения, только факты.

Обратите внимание, что это не опечатка, которую я включил vector вместо string.Я сделал это намеренно, чтобы компилятор не мог понять, что такое std :: string, и чтобы ему пришлось искать, чтобы выяснить, на какой оператор я ссылаюсь с помощью +:

#include <vector>
// #include <string> // intentionally commented out

template <typename T> struct A
{
    A() { };
    ~A() { };

    int m_member;
};

template <typename T> A<T> operator+(double lhs, const A<T> &rhs);

int main(int argc, char **argv)
{
    std::string fullString = std::string("Hi ") + std::string("mom!");
}

Итак, я получаю множество ошибок компилятора в MS Visual Studio 2005. Я показываю только их подмножество.

1>.\test.cpp(21) : error C2784: 'A<T> operator +(double,const A<T> &)' : could not deduce template argument for 'const A<T> &' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        .\test.cpp(16) : see declaration of 'operator +'

... ошибки продолжаются ...

1>.\test.cpp(21) : error C2784: 'std::_Vb_iterator<_MycontTy> std::operator +(_Vb_iterator<_MycontTy>::difference_type,std::_Vb_iterator<_MycontTy>)' : could not deduce template argument for 'std::_Vb_iterator<_MycontTy>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(1800) : see declaration of 'std::operator +'

... ошибки продолжаются ...

1>.\test.cpp(21) : error C2784: 'std::_Vb_const_iterator<_MycontTy> std::operator +(_Vb_const_iterator<_MycontTy>::difference_type,std::_Vb_const_iterator<_MycontTy>)' : could not deduce template argument for 'std::_Vb_const_iterator<_MycontTy>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(1695) : see declaration of 'std::operator +'

... ошибки продолжаются ...

1>.\test.cpp(21) : error C2784: 'std::_Vector_iterator<_Ty,_Alloc> std::operator +(_Vector_iterator<_Ty,_Alloc>::difference_type,std::_Vector_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_iterator<_Ty,_Alloc>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(396) : see declaration of 'std::operator +'

... ошибки продолжаются ...

1>.\test.cpp(21) : error C2784: 'std::_Vector_const_iterator<_Ty,_Alloc> std::operator +(_Vector_const_iterator<_Ty,_Alloc>::difference_type,std::_Vector_const_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_const_iterator<_Ty,_Alloc>' from 'std::basic_string<_Elem,_Traits,_Ax>'
1>        with
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits<char>,
1>            _Ax=std::allocator<char>
1>        ]
1>        C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(264) : see declaration of 'std::operator +'

Итак, компилятор ищет, что означает +, и жалуется, что не может вывести соответствующие аргументы шаблона.Меня удивляют две взаимосвязанные вещи: one состоит в том, что он выдает эту ошибку для каждого перегруженного оператора +, который включает шаблоны.Это говорит мне о том, что компилятор абсолютно не может исключить, что любой из этих + не имеет смысла; two , что связано с тем, что он не просто жалуется на отсутствие подходящего оператора.

Я рассматриваю это как возможность узнать кое-что о том, как создаются и компилируются шаблоны.У кого-нибудь есть хорошее объяснение или ссылки?

Ответы [ 3 ]

2 голосов
/ 28 апреля 2011

Обратите внимание, что это не опечатка, которую я включил vector вместо string. Я сделал это намеренно, чтобы компилятор не мог понять, что такое std :: string, и чтобы ему пришлось искать, чтобы выяснить, на какой оператор я ссылаюсь с помощью +.

Это не правильно. Компилятор знает , что такое std::string. Предположим, например, что следующая программа прекрасно компилируется (с использованием Visual C ++ 2010, но она должна работать и в 2005 году):

#include <vector>

int main() {
    std::string s;
}

При использовании Visual C ++ (по крайней мере, Visual C ++ 2005–2010; я не могу говорить о других версиях), в том числе <vector> также включает в себя все, что объявляет внутренний заголовок и определяет std::basic_string и std::string. Это разрешено стандартом языка С ++.

Однако вы, очевидно, не получаете перегрузок operator+, которые принимают std::string (или, точнее, std::basic_string) операндов. Чтобы получить те, которые вы должны включить <string>.

Компилятор прекрасно знает, что такое std::string, но когда он пытается найти перегрузку operator+ для двух std::string объектов, он завершается неудачно и сообщает обо всех перегрузках operator+, которые он рассматривал, но отклонил.

2 голосов
/ 28 апреля 2011

Фактически, поскольку он не может найти совпадение, он использует ошибки, чтобы сообщить вам возможных кандидатов-операторов, которые он действительно нашел.

Например, ошибка g ++ говорит о том, что он не может найти оператор, а затем выдает такое же множество сообщений, но в форме «кандидаты:» вместо одной ошибки на оператора.

Он делает это, пытаясь быть полезным: поскольку он не может найти совпадение, он предполагает, что вы на самом деле имели в виду любой из возможных доступных операторов.

1 голос
/ 28 апреля 2011

что он не просто жалуется, что не существует подходящего оператора.

Это IMO - просто глупое поведение компилятора, если это то, что происходит. Конечно, он должен сначала сказать вам, что не так (т.е. не существует подходящего оператора), а затем перечислить все рассмотренные шаблоны.

во-первых, он выдает эту ошибку для каждого перегруженного оператора +, который включает шаблоны. Это говорит мне о том, что компилятор абсолютно не может исключить, что любой из этих + не имеет смысла;

Как правило, он не может этого сделать, потому что, например, std::_Vector_iterator<_Ty,_Alloc> может быть базовым классом std::basic_string<>, что означает, что перегрузка одного оператора может быть жизнеспособной, и дедукция будет успешной. На этом этапе вычитание аргументов - это фаза компиляции C ++, и компилятор просто сообщает вам результат вывода аргументов.

...