K
K. Frank
Hello Group!
I'm looking for some insight into how an assignment such as:
std::function<int, (int, int)> f = [z](int x, int y){ return x + y
+ z; };
actually works under the hood.
I've been playing around with lambda using a mingw-w64 version
of g++: "g++ (GCC) 4.7.0 20110829 (experimental)".
According to the new c++11 standard, each lambda expression has
its own unique type. (I guess I can see the reason for this.)
If the capture list is empty, the language provides an implicit
conversion to a function pointer, but not if the capture list is
non-trivial. (This makes sense to me as well.)
So I'm assuming that the language doesn't convert a lambda with
a non-trivial capture list into any sort of useful type that
std::function might be able to get its hands on. I therefore
imagine that std::function must define some sort template conversion
operator that can be templatized on a variety of novel types,
including the unique type of the lambda.
I guess this would make sense, but I don't really see how the
details of this would work out. Does std::function wrap a
copy of or a reference to the actual instance of the lambda?
Presumably std::function doesn't know anything about capture
lists, so it would need the lambda to manage that.
One last question: If I try to assign, say, a double to a
std::function, I get a compiler error "cannot be used as a
function".
My thinking is that, in principle, source-based libraries
(i.e., template libraries where the code is in the included
header file) should be implementable solely using the core
language, without any additional compiler support, but that
an implementation is allowed to have additional compiler
support for efficiency, convenience, etc.
So, does this error message indicate that the g++ compiler
knows something special about std::function, or could I, in
principle, write my own template functional implementation,
and get the same kind of compiler errors?
A test program that illustrates some of this appears below.
Thanks for any insight.
K. Frank
***** test program *****
***** compiled with: g++ -std=c++0x -o tst tst.cpp *****
#include <iostream>
#include <typeinfo>
#include <functional>
int main() {
int z = 100;
// type of lambda
// prints out "typeid([z](int x, int y) { return x + Y +
z; }).name() = Z4mainEUliiE_"
std::cout << "typeid([z](int x, int y) { return x + Y + z; }).name()
= " << typeid([z](int x, int y) { return x + y + z; }).name() <<
std::endl;
// a new type...
// prints out "typeid([z](int x, int y) { return x + Y +
z; }).name() = Z4mainEUliiE0_"
std::cout << "typeid([z](int x, int y) { return x + Y + z; }).name()
= " << typeid([z](int x, int y) { return x + y + z; }).name() <<
std::endl;
// another new type...
auto lambda1 = [z](int x, int y) { return x + y + z; };
// prints out "typeid(lambda1).name() = Z4mainEUliiE1_"
std::cout << "typeid(lambda1).name() = " << typeid(lambda1).name()
<< std::endl;
// a type different from the lamdaa
std::function<int (int, int)> function1;
// prints out "typeid(function1).name() = St8functionIFiiiEE"
std::cout << "typeid(function1).name() = " <<
typeid(function1).name() << std::endl;
function1 = [z](int x, int y) { return x + y + z; };
std::cout << "function1 (10, 1) = " << function1 (10, 1) <<
std::endl;
double d = 1.2345;
// function1 = d;
// the above line fails with the compile error:
// error: '*
std::_Function_base::_Base_manager<_Functor>::_M_get_pointer<double>((*
& __functor))' cannot be used as a function
}
***** test program *****
I'm looking for some insight into how an assignment such as:
std::function<int, (int, int)> f = [z](int x, int y){ return x + y
+ z; };
actually works under the hood.
I've been playing around with lambda using a mingw-w64 version
of g++: "g++ (GCC) 4.7.0 20110829 (experimental)".
According to the new c++11 standard, each lambda expression has
its own unique type. (I guess I can see the reason for this.)
If the capture list is empty, the language provides an implicit
conversion to a function pointer, but not if the capture list is
non-trivial. (This makes sense to me as well.)
So I'm assuming that the language doesn't convert a lambda with
a non-trivial capture list into any sort of useful type that
std::function might be able to get its hands on. I therefore
imagine that std::function must define some sort template conversion
operator that can be templatized on a variety of novel types,
including the unique type of the lambda.
I guess this would make sense, but I don't really see how the
details of this would work out. Does std::function wrap a
copy of or a reference to the actual instance of the lambda?
Presumably std::function doesn't know anything about capture
lists, so it would need the lambda to manage that.
One last question: If I try to assign, say, a double to a
std::function, I get a compiler error "cannot be used as a
function".
My thinking is that, in principle, source-based libraries
(i.e., template libraries where the code is in the included
header file) should be implementable solely using the core
language, without any additional compiler support, but that
an implementation is allowed to have additional compiler
support for efficiency, convenience, etc.
So, does this error message indicate that the g++ compiler
knows something special about std::function, or could I, in
principle, write my own template functional implementation,
and get the same kind of compiler errors?
A test program that illustrates some of this appears below.
Thanks for any insight.
K. Frank
***** test program *****
***** compiled with: g++ -std=c++0x -o tst tst.cpp *****
#include <iostream>
#include <typeinfo>
#include <functional>
int main() {
int z = 100;
// type of lambda
// prints out "typeid([z](int x, int y) { return x + Y +
z; }).name() = Z4mainEUliiE_"
std::cout << "typeid([z](int x, int y) { return x + Y + z; }).name()
= " << typeid([z](int x, int y) { return x + y + z; }).name() <<
std::endl;
// a new type...
// prints out "typeid([z](int x, int y) { return x + Y +
z; }).name() = Z4mainEUliiE0_"
std::cout << "typeid([z](int x, int y) { return x + Y + z; }).name()
= " << typeid([z](int x, int y) { return x + y + z; }).name() <<
std::endl;
// another new type...
auto lambda1 = [z](int x, int y) { return x + y + z; };
// prints out "typeid(lambda1).name() = Z4mainEUliiE1_"
std::cout << "typeid(lambda1).name() = " << typeid(lambda1).name()
<< std::endl;
// a type different from the lamdaa
std::function<int (int, int)> function1;
// prints out "typeid(function1).name() = St8functionIFiiiEE"
std::cout << "typeid(function1).name() = " <<
typeid(function1).name() << std::endl;
function1 = [z](int x, int y) { return x + y + z; };
std::cout << "function1 (10, 1) = " << function1 (10, 1) <<
std::endl;
double d = 1.2345;
// function1 = d;
// the above line fails with the compile error:
// error: '*
std::_Function_base::_Base_manager<_Functor>::_M_get_pointer<double>((*
& __functor))' cannot be used as a function
}
***** test program *****