I've seen many examples of using a lambda expression as a template argument, but when i was reading the reference page for lambda functions at cppreference.com,
it has this short sentence:
Lambda-expressions are not allowed in unevaluated expressions, template arguments, alias declarations, typedef declarations, and anywhere in a function (or function template) declaration except the function body and the function's default arguments.
I was very confused, is this sentence wrong or I did not understand it correctly?
What you can do:
template <class>
struct Foo;
auto l = []{};
Foo<decltype(l)> f;
What you cannot do:
template <SomeType lambda>
struct Foo;
Foo<[]{}> f;
In other words, the type of the lambda is a normal type like any other, but the lambda-expression itself can't be used to specialize a template. The same applies to unevaluated contexts such as the operands of decltype and sizeof.
Related
I have a wrapper class that needs to be used interchangeably with the wrapped class.
Fortunately the class and the wrapper are binary compatible (by design) and the conversion can be easily performed (for example in this case by reinterpret_cast, or even simpler as in the example).
In part, to achieve this, I need to be able to convert from the wrapper type to the wrapped type, via operator T().
Currently the code looks like this:
template<class T> // // I am putting this general T type, to show it can be a large (movable) object, for example, std::vector.
struct wrapper{
T a;
operator T const&() const&{return a;} // in other cases it can involve more code, like reinterpret_casts or some conditional blocks.
operator T&&() &&{return std::move(a);} // same
operator T&() &{return a;} // same
};
Can I condense these three conversion functions into one function or less code, or is there another way?
I could make it more general, (but longer code for this simple case) this way,
template<class T>
struct wrapper{
T a;
operator T const&() const&{return a;} // complicated code can be here only
operator T&&() &&{return std::move(operator A&());}
operator T&() &{return const_cast<T&>(operator T const&());}
};
The final objective is that T can be used interchangeably with wrapper<T>.
This is very similar to How do I remove code duplication between similar const and non-const member functions?,
however this case is more specific because 1) it involves the conversion operator and also, 2) involves l-value overloads.
I'm reading the source code of the main json11 header file.
It contains the following declaration:
template <class T, class = decltype(&T::to_json)>
Json(const T & t) : Json(t.to_json()) {}
I'm trying to find some documentation about this usage of decltype and class inside a template declaration but no success.
Does this construction/usage has a name in C++? Any good reference about it?
It's using SFINAE ("Substitution Failure Is Not An Error"), a common technique for advanced template stuff. In this case, it's used as a crude(1) test whether the type T has a function named to_json.
How it works: if the expression T::to_json is well-formed (there is something named to_json inside the type T), decltype(T::to_json) denotes a valid type and the constructor template can be used normally.
However, if T::to_json is ill-formed (i.e. if there is no to_json member inside T), it means substituting the template argument for T has failed. Per SFINAE, this is not an error of the entire program; it just means that the template is removed from further consideration (as if it was never part of the class).
The effect is thus that if type T has a member to_json, you can use an object of type T to initialise a Json object. If there is no such member in T, the constructor will not exist.
(1) I'm saying crude test because this only checks that T has such a member. It doesn't check that the member is a function which can be invoked without arguments and returns something another constructor of Json can accept. A tighter-fitting test might look something like this:
template <class T, class = std::enable_if_t<std::is_constructible<Json, decltype(std::declval<const T>().to_json())>::value>>
Json(const T & t) : Json(t.to_json()) {}
[Live example]
Consider following
struct dummy{};
dummy d1;
dummy d2;
template<dummy* dum>
void foo()
{
if (dum == &d1)
; // do something
else if (dum == &d2)
; // do something else
}
Now, it is possible to call foo like this
foo<&d1>();
foo<&d2>();
and everything works as expected. But following does not
constexpr dummy* dum_ptr = &d1;
foo<dum_ptr>();
With this error from Visual studio
error C2975: dum_ptr: invalid template argument for foo, expected compile-time constant expression
While this works
constexpr dummy& dum_ref = d1;
foo<&dum_ptr>();
In visual studio, but not in G++, because of
note: template argument deduction/substitution failed:
error: & dum_ref is not a valid template argument for dummy* because it is not the address of a variable
foo<&dum_ref>();
EDIT:
Since C++17, std::addressof is being marked as constexpr, so I would guess it should work.
GCC is right on this one.
The expressions are definitely constant-expressions*, since they are assigned to a constexpr variable. However, until c++14, there are additional restrictions on what is allowed for a pointer template argument.
C++14 draft N4140 [temp.arg.nontype]
1 A template-argument for a non-type, non-template template-parameter shall be one of:
for a non-type template-parameter of integral or enumeration type, a converted constant expression (5.19) of the type of the
template-parameter; or
the name of a non-type template-parameter; or
a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal
linkage or a function with external or internal linkage, including
function templates and function template-ids but excluding non-static
class members, expressed (ignoring parentheses) as
&id-expression, where the id-expression is the name of an object or
function, except that the & may be omitted if the name refers to a
function or array and shall be omitted if the corresponding
template-parameter is a reference; or
a constant expression that evaluates to a null pointer value (4.10); or
a constant expression that evaluates to a null member pointer value (4.11); or
a pointer to member expressed as described in 5.3.1; or
a constant expression of type std::nullptr_t.
For foo<dum_ptr>(), dum_ptr isn't expressed as &name, and for foo<&dum_ref>(), dum_ref isn't the name of the object, it's the name of a reference to the object, so both are disallowed as template arguments.
These restrictions are lifted in c++17 to allow any constexpr, so thats why it works there:
C++17 draft N4606 - 14.3.2 Template non-type arguments [temp.arg.nontype]
1 A template-argument for a non-type template-parameter shall be a
converted constant expression (5.20) of the type of the
template-parameter. For a non-type template-parameter of reference or
pointer type, the value of the constant expression shall not refer to
(or for a pointer type, shall not be the address of):
(1.1) a subobject (1.8),
(1.2) a temporary object (12.2),
(1.3) a string literal (2.13.5),
(1.4) the result of a typeid expression (5.2.8), or
(1.5) a predefined __func__ variable (8.4.1).
As usual, clang gives the best error messages:
https://godbolt.org/g/j0Q2bV
*(see Address constant expression and Reference constant expression)
In this sample:
auto f = [](int some, int some2){
//do something
};
This case it is a functor or object of function?
std::function<void(int, int)> f = [](int some, int some2) {
//do something
}
Now, in this case, whats is the results? Functor or Object of function?
The first f (i.e., the one designated with auto) results to what is called a lambda function. Also knows as a closure. Closures are unnamed function objects. That's why we need auto to deduce the type of a closure. We don't know it's type but the compiler does. Thus, by using auto we let the compiler deduce the type of the unnamed closure object for us.
The second f (i.e., the one designated with std::function) is a std::function object. Class std::function is a general-purpose polymorphic function wrapper.
Lambdas closures as function objects can be converted to their respective std::function objects. That is exactly what is happening in:
std::function<void(int, int)> f = [](int some, int some2) {
//do something
}
The lambda closure on the right hand side is assigned and converted to the std::function object on the left side of the assignment.
Practically, they're both interpreted as functors, since they both overload call operator() and thus can be called, except for that the lambda's type is unnamed.
Another difference between those two is that you can't assign between lambda closures, since for lambda closures the assignment operator is declared deleted. while you can assign between std::function objects.
A particular property of c++'s lambda expressions is to capture the variables in the scope in which they are declared. For example I can use a declared and initialized variable c in a lambda function even if 'c' is not sent as an argument, but it's captured by '[ ]':
#include<iostream>
int main ()
{int c=5; [c](int d){std::cout<<c+d<<'\n';}(5);}
The expected output is thus 10. The problem arises when at least 2 variables, one captured and the other sent as an argument, have the same name:
#include<iostream>
int main ()
{int c=5; [c](int c){std::cout<<c<<'\n';}(3);}
I think that the 2011 standard for c++ says that the captured variable has the precedence on the arguments of the lambda expression in case of coincidence of names. In fact compiling the code using GCC 4.8.1 on Linux the output I get is the expected one, 5. If I compile the same code using apple's version of clang compiler (clang-503.0.40, the one which comes with Xcode 5.1.1 on Mac OS X 10.9.4) I get the other answer, 3.
I'm trying to figure why this happens; is it just an apple's compiler bug (if the standard for the language really says that the captured 'c' has the precedence) or something similar? Can this issue be fixed?
EDIT
My teacher sent an email to GCC help desk, and they answered that it's clearly a bug of GCC compiler and to report it to Bugzilla. So Clang's behavior is the correct one!
From my understanding of the c++11 standard's points below:
5.1.2 Lambda expressions
3 The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called
the closure type — whose properties are described below.
...
5 The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are
described by the lambda-expression’s parameter-declaration-clause and
trailing-return-type respectively. This function call operator is
declared const (9.3.1) if and only if the lambda-expression’s
parameter-declaration-clause is not followed by mutable.
...
14 For each entity captured by copy, an unnamed non static data member is declared in the closure type
A lambda expression like this...
int c = 5;
[c](int c){ std::cout << c << '\n'; }
...is roughly equivalent to a class/struct like this:
struct lambda
{
int c; // captured c
void operator()(int c) const
{
std::cout << c << '\n';
}
};
So I would expect the parameter to hide the captured member.
EDIT:
In point 14 from the standard (quoted above) it would seem the data member created from the captured variable is * unnamed *. The mechanism by which is it referenced appears to be independent of the normal identifier lookups:
17 Every id-expression that is an odr-use (3.2) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type.
It is unclear from my reading of the standard if this transformation should take precedence over parameter symbol lookup.
So perhaps this should be marked as UB (undefined behaviour)?
From the C++11 Standard, 5.1.2 "Lambda expressions" [expr.prim.lambda] #7:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator,
but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id-expressions
referring to non-static class members into class member access expressions using (*this) (9.3.1),
the compound-statement is considered in the context of the lambda-expression.
Also, from 3.3.3 "Block scope" [basic.scope.local] #2:
The potential scope of a function parameter name (including one appearing in a lambda-declarator) or of
a function-local predefined variable in a function definition (8.4) begins at its point of declaration.
Names in a capture list are not declarations and therefore do not affect name lookup. The capture list just allows you to use the local variables; it does not introduce their names into the lambda's scope. Example:
int i, j;
int main()
{
int i = 0;
[](){ i; }; // Error: Odr-uses non-static local variable without capturing it
[](){ j; }; // OK
}
So, since the parameters to a lambda are in an inner block scope, and since name lookup is done in the context of the lambda expression (not, say, the generated class), the parameter names indeed hide the variable names in the enclosing function.