Re[5]: ADL. Кто неправ я, компилятор или реализация STL
От: Greg Zubankov СССР  
Дата: 21.10.06 14:41
Оценка: 14 (3)
Здравствуйте, night beast, Вы писали:

NB>это я к тому что begin() + _Newsize вызавается в пространстве std, и по идее до ADL дело не должно было дойти.

NB>или я не прав?
ADL проводится вне зависимости от кого, в какой область видимости (scope) компилятору встретилось неквалифицированное имя.


PS. Однако есть способ отключения ADL, для этого достаточно заключить имя вызываемой функции в скобки:
namespace foo
{
  struct A {};
  void bar(A) {}
}

int main()
{
  foo::A b;
  bar(b);    // ok: calls foo::bar
  (bar)(b);  // error
}
ADL. Кто неправ я, компилятор или реализация STL
От: Kazmerchuk Pavel  
Дата: 20.10.06 19:39
Оценка:
В моей библиотеке при переходе на версию STL из поставки VS2005 (с STLPort все в порядке)
полезли ошибки компиляции. Вот минимальный код, приводящий к ошибке

#include "stdafx.h"
#include <vector>

namespace mtr{

  template<typename T>
  class Argument
  {
    const T& arg_;   

  public:

    Argument(T const& arg) 
      : arg_(arg) 
    {}
  };

  template<typename T, typename U>
  class Expression
  {
    typedef Argument<T> Left;
    typedef Argument<U> Right;

    const Left  left_;
    const Right right_;  

  public:

    Expression( const Left& left, const Right& right )
      : left_(left), right_(right) 
    {}
  };

  struct Matrix
  {
    float p[3];
  };

  template<typename Left, typename Right>
  inline Expression<Left, Right> operator + (Left const& a, Right const& b )
  {
    return Expression<Left, Right>(a, b);
  }
}

int _tmain(int argc, _TCHAR* argv[])
{
  std::vector<mtr::Matrix> v;
  v.resize(2);
  
  return 0;
}


Ошибка компиляции в недрах std::vector<>::resize, которая определена так:
void resize(size_type _Newsize, _Ty _Val)
{
  if (size() < _Newsize)
    _Insert_n(end(), _Newsize - size(), _Val);
  else if (_Newsize < size())
    erase(begin() + _Newsize, end());
}

Проблема в выражении begin() + _Newsize и заключается в том, что _Newsize имеет тип size_type, а для итератора, возаращаемого begin() операция сложения определена так:
_Myt operator+(difference_type _Off) const
{  // return this + integer
  _Myt _Tmp = *this;
  return (_Tmp += _Off);
}

Что делает компилятор: он считает, что вместо преобразования size_type->difference_type [это преобразование unsigned int->int для того чтобы
вызвать operator+(difference_type _Off) const ] более подходящим являетя мой шаблонный!! оператор Expression<Left, Right> operator + (Left const& a, Right const& b ),
который он и подставляет. Дальше все по плану: Expression<Left, Right> не возможно превести к std::vector<>::iterator, который требуется для вызова erase(...)

Вопрос 1. Почему компилятор лезет в мое пространство имен, проводя зависимый поиск, хотя аргументы в begin() + _Newsize к нему ни какого отношения не имеют?
Вопрос 2. Почему если внутри resize (для вызова begin() + _Newsize) требуется приведение типа разработчики на сделали это явно (это конечно если компилятор прав в первом вопросе)?
Вопрос 3. Что делать? Править исходник вектора не хочется.

ps: с STLPort все в порядке потому, что в векторе итератор это просто голый указатель. С ним у компилятора вопросов не возникает.
Re: ADL. Кто неправ я, компилятор или реализация STL
От: Greg Zubankov СССР  
Дата: 21.10.06 10:01
Оценка:
Здравствуйте, Kazmerchuk Pavel, Вы писали:

KP>Вопрос 1. Почему компилятор лезет в мое пространство имен, проводя зависимый поиск, хотя аргументы в begin() + _Newsize к нему ни какого отношения не имеют?

Компилятор прав. Посколько vector::iterator наследуется от шаблона std::iterator, поиск (ADL) проводится также в пространствах имен параметров шаблона. Первый из списка параметров std::iterator как раз Ваш mtr::Matrix.

KP>Вопрос 2. Почему если внутри resize (для вызова begin() + _Newsize) требуется приведение типа разработчики на сделали это явно (это конечно если компилятор прав в первом вопросе)?

В стандарте поведение resize задается как:
if (sz > size())
  insert(end(), sz-size(), c);
else if (sz < size())
  erase(begin()+sz, end()); // приведения нет
else
  ; //do nothing


KP>Вопрос 3. Что делать? Править исходник вектора не хочется.

Думаю лучше объявить менее "шаблонную" функцию operator+. К примеру оставить один параметр в шаблоне.

KP>ps: с STLPort все в порядке потому, что в векторе итератор это просто голый указатель. С ним у компилятора вопросов не возникает.

Правильно, у итератора в этом случает нет предка-шаблона.
Re[2]: ADL. Кто неправ я, компилятор или реализация STL
От: night beast СССР  
Дата: 21.10.06 11:27
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:

KP>>Вопрос 1. Почему компилятор лезет в мое пространство имен, проводя зависимый поиск, хотя аргументы в begin() + _Newsize к нему ни какого отношения не имеют?

GZ>Компилятор прав. Посколько vector::iterator наследуется от шаблона std::iterator, поиск (ADL) проводится также в пространствах имен параметров шаблона. Первый из списка параметров std::iterator как раз Ваш mtr::Matrix.

а разве сначала не производится обычный поиск в пространстве std (где определены vector::iterator и std::iterator) ?
Re[3]: ADL. Кто неправ я, компилятор или реализация STL
От: Greg Zubankov СССР  
Дата: 21.10.06 13:36
Оценка:
Здравствуйте, night beast, Вы писали:

KP>>>Вопрос 1. Почему компилятор лезет в мое пространство имен, проводя зависимый поиск, хотя аргументы в begin() + _Newsize к нему ни какого отношения не имеют?

GZ>>Компилятор прав. Посколько vector::iterator наследуется от шаблона std::iterator, поиск (ADL) проводится также в пространствах имен параметров шаблона. Первый из списка параметров std::iterator как раз Ваш mtr::Matrix.

NB>а разве сначала не производится обычный поиск в пространстве std (где определены vector::iterator и std::iterator) ?


Я написал "проводится также". Естественно сначала проводится ordinary unqualified lookup. Затем проводится ADL. Из двух найденных operator+ однозначно выбирается mtr::operator+.

Clause 3.4.2 verse 2a:

If the ordinary unqualified lookup of the name finds the declaration of a class member function, the associated
namespaces and classes are not considered. Otherwise the set of declarations found by the lookup of
the function name is the union of the set of declarations found using ordinary unqualified lookup and the set
of declarations found in the namespaces and classes associated with the argument types.


PS. если бы vector::iterator::operator+ был объвлен без квалификатра const, компилятор выдал бы ошибку неоднозначности выбора
Re[4]: ADL. Кто неправ я, компилятор или реализация STL
От: night beast СССР  
Дата: 21.10.06 13:59
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:

GZ>Здравствуйте, night beast, Вы писали:


KP>>>>Вопрос 1. Почему компилятор лезет в мое пространство имен, проводя зависимый поиск, хотя аргументы в begin() + _Newsize к нему ни какого отношения не имеют?

GZ>>>Компилятор прав. Посколько vector::iterator наследуется от шаблона std::iterator, поиск (ADL) проводится также в пространствах имен параметров шаблона. Первый из списка параметров std::iterator как раз Ваш mtr::Matrix.

NB>>а разве сначала не производится обычный поиск в пространстве std (где определены vector::iterator и std::iterator) ?


GZ>Я написал "проводится также". Естественно сначала проводится ordinary unqualified lookup.

GZ>Затем проводится ADL. Из двух найденных operator+ однозначно выбирается mtr::operator+.

это я к тому что begin() + _Newsize вызавается в пространстве std, и по идее до ADL дело не должно было дойти.
или я не прав?
Re[6]: ADL. Кто неправ я, компилятор или реализация STL
От: Kazmerchuk Pavel  
Дата: 21.10.06 15:02
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:

GZ>ADL проводится вне зависимости от кого, в какой область видимости (scope) компилятору встретилось неквалифицированное имя.


У Вандервуда с Джосаттисом: "Если при обычном поиске будет найдено имя функции-члена или имя типа, то ADL не применяется."

_Myt operator+(difference_type _Off) const

как раз является членом std::vector<...>::iterator. Как это объяснить?
Re[7]: ADL. Кто неправ я, компилятор или реализация STL
От: shank  
Дата: 21.10.06 17:17
Оценка:
Здравствуйте, Kazmerchuk Pavel, Вы писали:

KP>У Вандервуда с Джосаттисом: "Если при обычном поиске будет найдено имя функции-члена или имя типа, то ADL не применяется."


KP>
KP>_Myt operator+(difference_type _Off) const
KP>

KP> как раз является членом std::vector<...>::iterator. Как это объяснить?
В том и дело, что имя функции-члена не было найдено, а найдено было выражение begin() + _Newsize.
Как интерпретируются такие выражения расписано в 13.3.1.2/2

For a unary operator @ with an operand of a type whose cv-unqualified version is T1, and for a binary operator
@ with a left operand of a type whose cv-unqualified version is T1 and a right operand of a type whose
cv-unqualified version is T2, three sets of candidate functions, designated member candidates, non-member
candidates and built-in candidates
, are constructed as follows:
...

Re[2]: ADL. Кто неправ я, компилятор или реализация STL
От: Kazmerchuk Pavel  
Дата: 23.10.06 20:26
Оценка:
Всем спасибо! У меня последний вопрос к Greg Zubankov

Вы писали:

GZ>В стандарте поведение resize задается как:

GZ>
GZ>if (sz > size())
GZ>  insert(end(), sz-size(), c);
GZ>else if (sz < size())
GZ>  erase(begin()+sz, end()); // приведения нет
GZ>else
GZ>  ; //do nothing
GZ>


Почему нет приведения? sz имеет тип size_type (что есть — unsigned int)
operator+ для итератора принимает difference_type (что есть int). Компилятор должен выполнить интегральное преобразование unsigned int -> int, чтобы вызвать iterator::operator+. Или я не прав?

p.s. я это к тому, что явное приведение sz к difference_type решает мою проблему.
Re: ADL. Кто неправ я, компилятор или реализация STL
От: Viper_Craft  
Дата: 23.10.06 20:54
Оценка:
Здравствуйте, Kazmerchuk Pavel, Вы писали:

KP>Вопрос 3. Что делать?



Отвечу цитатой из C++ Coding Standards:

Keep types and functions in separate namespaces unless the're specifically intended to work together.


KP> Править исходник вектора не хочется.


И не надо...
Re[3]: ADL. Кто неправ я, компилятор или реализация STL
От: Lorenzo_LAMAS  
Дата: 24.10.06 08:10
Оценка:
KP>p.s. я это к тому, что явное приведение sz к difference_type решает мою проблему.

Да, решает. Просто авторы библиотеки, хоть они и эксперты в С++, не учли возможности проблем, подобных твоей.
Of course, the code must be complete enough to compile and link.
Re[3]: ADL. Кто неправ я, компилятор или реализация STL
От: Greg Zubankov СССР  
Дата: 24.10.06 09:34
Оценка:
Здравствуйте, Kazmerchuk Pavel, Вы писали:

KP>Почему нет приведения? sz имеет тип size_type (что есть — unsigned int)

KP>operator+ для итератора принимает difference_type (что есть int). Компилятор должен выполнить интегральное преобразование unsigned int -> int, чтобы вызвать iterator::operator+. Или я не прав?
Я наверное не слишком понятно выразился.
Хотел сказать что в стандарте нет указания делать явное приведение. Естественно при вызове функции iterator::operator+ (в случае ее выбора), компилятор произведет неявное преобразование.

KP>p.s. я это к тому, что явное приведение sz к difference_type решает мою проблему.

Да, согласен.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.