Почему не вызывается лямбда мне понятно, не могу только никак понять, почему в stdout попадает именно 1. Или это implementation-defined в зависимости от того, как в компиляторе реализованы лямбды? Так, вроде как, лямбды в большинстве случаев представляются как объекты-функторы, а для применения к ним operator<< его ещё перегрузить надо. Или срабатывает преобразование к указателю void*? В общем, что говорит стандарт по данному поводу?
Здравствуйте, PlusMyTwitterFace, Вы писали:
PMT>Почему не вызывается лямбда мне понятно, не могу только никак понять, почему в stdout попадает именно 1.
угу.. потому что ты ее не вызываешь, вот она и не вызывается
PMT>Почему данный код выводит именно 1?
PMT>http://liveworkspace.org/code/cb8b23a0336499531320c422d53999b0
PMT>Почему не вызывается лямбда мне понятно, не могу только никак понять, почему в stdout попадает именно 1. Или это implementation-defined в зависимости от того, как в компиляторе реализованы лямбды? Так, вроде как, лямбды в большинстве случаев представляются как объекты-функторы, а для применения к ним operator<< его ещё перегрузить надо. Или срабатывает преобразование к указателю void*? В общем, что говорит стандарт по данному поводу?
Сначала происходит преобразование объекта в указатель на функцию, а затем этот указатель на функцию преобразуется в тип void *, и для него вызывается оператор operator <<( const void * ).
Если вы измените ваш пример, добавив захватываемую переменную, то код уже не должен компилироваться, так как для лямбда-выражений, имеющих захватываемые переменные, оператор-функция преобразования в указатель на функцию не создается. Рассмотрите следующий код
#include <iostream>
int main()
{
int x = 0;
auto lm = [x] { return x; };
std::cout << lm << std::endl;
}
Компилятор для этого кода должен сгенерировать ошибку компиляции, так как для объекта lm, который представляет собой объект лямбда-выражения, не определен оператор operator <<.
С другой стороны, вы можете скомпилировать следующий код
Этот код даст тот же самый результат, который вы получили для своего собственного исходного примера. Только в моем примере я явно преобразую лямбда-выражение в указатель на функцию.
Поэтому значение, равное 1, для этого адреса — это особенность того компилятора, который вы используете. Другие компиляторы моогут выдать совершенно другое значение для адреса указателя на функцию для лямбда-выражения.
Здравствуйте, Сыроежка, Вы писали:
С>Сначала происходит преобразование объекта в указатель на функцию, а затем этот указатель на функцию преобразуется в тип void *, и для него вызывается оператор operator <<( const void * ).
1) указатель на функцию нельзя неявно скастить к void*, пример: http://liveworkspace.org/code/c3ed22b220ef3a2e3a73cb9282be7376
2) operator<<(void*) не существует, в C++ стараются работать с конкретными типами, избегая void*
выше уже отметили, что лямбда сконвертировалась в bool, и вызывался соответствующий operator<<(bool)
С>Поэтому значение, равное 1, для этого адреса — это особенность того компилятора, который вы используете.
адрес 1 должен был вам намекнуть, что вы думаете в неправильном направлении
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, Сыроежка, Вы писали:
С>>Сначала происходит преобразование объекта в указатель на функцию, а затем этот указатель на функцию преобразуется в тип void *, и для него вызывается оператор operator <<( const void * ). U>1) указатель на функцию нельзя неявно скастить к void*, пример: http://liveworkspace.org/code/c3ed22b220ef3a2e3a73cb9282be7376 U>2) operator<<(void*) не существует, в C++ стараются работать с конкретными типами, избегая void*
Во-первых, у меня было написано не operator <<( void * ), а operator <<( const void * ).
Вы можете расширить свои знания по С++, узнав, что в стандарте С++ имеется следующий оператор
basic_ostream<charT,traits>& operator<<(const void* p);
U>выше уже отметили, что лямбда сконвертировалась в bool, и вызывался соответствующий operator<<(bool)
То, что вы раньше написали, совершеннно не корректно. С чего это, вдруг, лямбда объект должен преобразовываться к типу bool?!
С>>Поэтому значение, равное 1, для этого адреса — это особенность того компилятора, который вы используете. U>адрес 1 должен был вам намекнуть, что вы думаете в неправильном направлении
Я вам советую проверить все те примеры кода, который я привел в своем сообщении, особенно тот пример, где имеет место явное преобразваоние лямбда объекта в указатель на функцию, а также пример, где имеется захватываемая переменная.
Идите вместе с uzhas учить С++ и не позорьтесь, ставя -1 совершенно корректному ответу. Лучше будет, если вы сначала будете думать, а уж потом тянуть свои ручонки ставить -1 правильным ответам.
M>>но тут оно, конечно же, не при делах.
С>Идите вместе с uzhas учить С++ и не позорьтесь, ставя -1 совершенно корректному ответу.
ответ некорректный, поскольку operator<<(ostream&, const void*) в выводе указателя не функцию (к которому преобразуется лямбда) не участвует. а то, что выводится "1" (при std::boolalpha "true") означает, что имеет место Boolean conversion:
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool.
лямбда преобразуется к указателю согласно разделу Function-to-pointer conversion
An lvalue of function type T can be converted to a prvalue of type “pointer to T.” The result is a pointer to the function.
согласно разделу Pointer conversions, в cv-void* может быть сконвертирован только указатель на объект:
A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”.
согласно разделу The C++ object model, функции объектами не являются:
An object is a region of storage. [ Note: A function is not an object, regardless of whether or not it occupies storage in the way that objects do. —end note ]
таким образом, резюмируя вышесказанное, лямбда преобразуется к типу "указатель на функцию", который преобразуется к типу bool, после чего вызывается operator<<(ostream&, bool).
M>>>но тут оно, конечно же, не при делах.
С>>Идите вместе с uzhas учить С++ и не позорьтесь, ставя -1 совершенно корректному ответу.
_>ответ некорректный, поскольку operator<<(ostream&, const void*) в выводе указателя не функцию (к которому преобразуется лямбда) не участвует. а то, что выводится "1" (при std::boolalpha "true") означает, что имеет место Boolean conversion:
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool.
_>лямбда преобразуется к указателю согласно разделу Function-to-pointer conversion
An lvalue of function type T can be converted to a prvalue of type “pointer to T.” The result is a pointer to the function.
_>согласно разделу Pointer conversions, в cv-void* может быть сконвертирован только указатель на объект:
A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”.
_>согласно разделу The C++ object model, функции объектами не являются:
An object is a region of storage. [ Note: A function is not an object, regardless of whether or not it occupies storage in the way that objects do. —end note ]
_>таким образом, резюмируя вышесказанное, лямбда преобразуется к типу "указатель на функцию", который преобразуется к типу bool, после чего вызывается operator<<(ostream&, bool).
Выполните, пожалуйста, сначала очень простой код
#include <iostream>
int f() { return 0; }
int main()
{
std::cout << f;
}
Посмотрите в режиме отладки, какой оператор вывода у вас будет использоваться, и сообщите всем нам. Договорились?
Я же пока замечу, что чтобы объект типа класса был преобразован к типу bool, в этом классе должна быть определена оператор-функция преобразования типов. Если такой функции в классе нет, то никакого преобразования к bool не будет.
const_volatile:
_>лямбда преобразуется к указателю согласно разделу Function-to-pointer conversion
An lvalue of function type T can be converted to a prvalue of type “pointer to T.” The result is a pointer to the function.
Там не function-to-pointer conversion, а user-defined conversion performed by conversion function. Лямбда — это не функция, а closure object классового типа. И тут применяются следующие правила:
8.5/16:
The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression. If the initializer is not a single (possibly parenthesized) expression, the source type is not defined.
— If the initializer is a (non-parenthesized) braced-init-list, the object or reference is list-initialized (8.5.4).
— If the destination type is a reference type, see 8.5.3.
— If the destination type is an array of characters, an array of char16_t, an array of char32_t, or an array of wchar_t, and the initializer is a string literal, see 8.5.2.
— If the initializer is (), the object is value-initialized.
— Otherwise, if the destination type is an array, the program is ill-formed.
— If the destination type is a (possibly cv-qualified) class type:
[...] — Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered. The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into the object being initialized. If the conversion cannot be done or is ambiguous, the initialization is ill-formed.[/b]
[...]
13.3.1.5:
Under the conditions specified in 8.5, as part of an initialization of an object of nonclass type, a conversion function can be invoked to convert an initializer expression of class type to the type of the object being initialized. Overload resolution is used to select the conversion function to be invoked. Assuming that “cv1 T” is the type of the object being initialized, and “cv S” is the type of the initializer expression, with S a class type, the candidate functions are selected as follows:
— The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence (13.3.3.1.1) are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T with a qualification conversion (4.4) are also candidate functions. Conversion functions that return a cv-qualified type are considered to yield the cv-unqualified version of that type for this process of selecting candidate functions. Conversion functions that return “reference to cv2 X” return lvalues or xvalues, depending on the type of reference, of type “cv2 X” and are therefore considered to yield X for this process of selecting candidate functions.
Результат вызова conversion function — указатель на функцию, он неявно преобразуется в bool.
С>Этот код даст тот же самый результат, который вы получили для своего собственного исходного примера. Только в моем примере я явно преобразую лямбда-выражение в указатель на функцию.
С>Поэтому значение, равное 1, для этого адреса — это особенность того компилятора, который вы используете. Другие компиляторы моогут выдать совершенно другое значение для адреса указателя на функцию для лямбда-выражения.
Compilation output:
source.cpp: In function 'int main()':
source.cpp:7:81: warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object [enabled by default]
Execution output:
true
0x8048b16
Так что там про адрес со значением 1 и особенности компилятора?
Здравствуйте, Сыроежка, Вы писали:
С>Посмотрите в режиме отладки, какой оператор вывода у вас будет использоваться, и сообщите всем нам. Договорились?
провел тест на VS2010, действительно, вызывается operator<<(const void *_Val), при этом печатается адрес функции 00E340C6
похоже на баг
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, Сыроежка, Вы писали:
С>>Посмотрите в режиме отладки, какой оператор вывода у вас будет использоваться, и сообщите всем нам. Договорились? U>провел тест на VS2010, действительно, вызывается operator<<(const void *_Val), при этом печатается адрес функции 00E340C6 U>похоже на баг
Я думаю, что надо смотреть MS VC++ 2012 RC. Дело в том, что в MS VC++ 2010 имеются серьезные недаработки в реализации лямбда-выражений. С одной стороны, нельзя явно преобразовать лямбда-выражение в указатель на функцию. С другой стороны, в своей библиотеке MS этим преобразованием пользуется.
M>>>>но тут оно, конечно же, не при делах.
С>>>Идите вместе с uzhas учить С++ и не позорьтесь, ставя -1 совершенно корректному ответу.
_>>ответ некорректный, поскольку operator<<(ostream&, const void*) в выводе указателя не функцию (к которому преобразуется лямбда) не участвует. а то, что выводится "1" (при std::boolalpha "true") означает, что имеет место Boolean conversion:
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool.
_>>лямбда преобразуется к указателю согласно разделу Function-to-pointer conversion
An lvalue of function type T can be converted to a prvalue of type “pointer to T.” The result is a pointer to the function.
_>>согласно разделу Pointer conversions, в cv-void* может быть сконвертирован только указатель на объект:
A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”.
_>>согласно разделу The C++ object model, функции объектами не являются:
An object is a region of storage. [ Note: A function is not an object, regardless of whether or not it occupies storage in the way that objects do. —end note ]
_>>таким образом, резюмируя вышесказанное, лямбда преобразуется к типу "указатель на функцию", который преобразуется к типу bool, после чего вызывается operator<<(ostream&, bool).
С>Выполните, пожалуйста, сначала очень простой код
С>Посмотрите в режиме отладки, какой оператор вывода у вас будет использоваться, и сообщите всем нам. Договорились?
С>Я же пока замечу, что чтобы объект типа класса был преобразован к типу bool, в этом классе должна быть определена оператор-функция преобразования типов. Если такой функции в классе нет, то никакого преобразования к bool не будет.