The following code is supposedly illegal in C++14 but legal in C++17:
#include <functional>
int main()
{
int x = 1729;
std::function<void (int&)> f(
[](int& r) { return ++r; });
f(x);
}
Don't bother testing it, you'll get inconsistent results making it difficult to suss whether it's a bug or intentional behavior. However, comparing two drafts (N4140 vs N4527, both can be found on github.com/cplusplus/draft), there's one significant difference in [func.wrap.func.inv]. Paragraph 2:
Returns: Nothing if R is void, otherwise the return value of INVOKE (f, std::forward(args)..., R).
The above was removed between drafts. The implication is that the return value of the lambda is now silently discarded. This seems like a misfeature. Can anyone explain the reasoning?
There was a ridiculous defect in the standard about std::function<void(Args...)>. By the wording of the standard, no (non-trivial)1 use of std::function<void(Args...)> was legal, because nothing can be "implicitly converted to" void (not even void).
void foo() {} std::function<void()> f = foo; was not legal in C++14. Oops.
Some compilers took the bad wording that made std::function<void(Args...)> completely useless, and applied the logic only to passed-in callables where the return value was not void. Then they concluded it was illegal to pass a function returning int to std::function<void(Args...)> (or any other non-void type). They did not take it to the logical end and ban functions returning void as well (the std::function requirements make no special case for signatures that match exactly: the same logic applies.)
Other compilers just ignored the bad wording in the void return type case.
The defect was basically that the return type of the invocation expression has to be implicitly convertible-to the return type of the std::function's signature (see link above for more details). And under the standard, void cannot be implicitly converted to void2.
So the defect was resolved. std::function<void(Args...)> now accepts anything that can be invoked with Args..., and discards the return value, as many existing compilers implemented. I presume this is because (A) the restriction was not ever intended by the language designers, or (B) having a way for a std::function that discards return values was desired.
std::function has never required exact match of arguments or return values, just compatibility. If the incoming arguments can implicitly convert-from the signature arguments, and the return type can implicitly convert-to the return type, it was happy.
And a function of type int(int&) is, under many intuitive definitions, compatible with the signature void(int&), in that you can run it in a "void context".
1 Basically, anything that makes operator() legal to call was not allowed. You can create it, you can destroy it, you can test it (and know it is empty). You cannot give it a function, even one that matches its signature exactly, or a function object or lambda. Ridiculous.
2 For void to be impliclty converted to void under the standard, it requires that the statement void x = blah;, where blah is an expression of type void, be valid; that statement is not valid, as you cannot create a variable of type void.
Related
I am getting confused around this snippet:
constexpr int f(bool b) {
return b ? throw 0 : 0; }
constexpr int f() { return f(true); }
directly from the c++ draft.
The point I am stucked with is why the standard defines as ill-formed the case of a constexpr function without arguments (stated in the same link).
May anyone clarify?
The key is "if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression". It's not about the function f() taking no arguments; it's about the fact that there's no set of arguments you could give it that would make it return a usable value - it always calls f(true), which throws an exception.
To re-iterate: a constexpr function without arguments can certainly be well-formed. But for the given example, it is not.
Also of note is "diagnostic not required". That means that a compiler is free to accept the construct anyway. Indeed, GCC compiles the example in your question without complaining.
Given the following declarations:
struct MyClass { };
typedef int MyClass::*Mp;
On both gcc 6.2 and Clang compiler I have tried, result_of<Mp(const MyClass)>::type yields int&&.
Summary of my question: Why int&& and not either const int&& or simply int?
More Background: The standard says that result_of is defined this way:
the member typedef type shall name the type
decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...));
The standard also defines INVOKE for pointer-to-member-objects this way:
— t1.*f when N == 1 and f is a pointer to data member of a class T and is_base_of_v<T, decay_t<decltype(t1)>> is true;
Note that the decay_t is only for testing whether this bullet applies. As far as I can tell, applying the two points above should yield:
decltype(declval<const MyClass>().*declval<Mp>())
Which yields const int&&. So, am I missing something, or are the compiler libraries wrong?
Edit, 30 Aug 2016:
Thanks for the responses. Several people have suggested alternative ways of getting the correct result without using result_of. I should clarify that the reason I am hung up on the correct definition of result_of is that I'm actually implementing the closest reasonable implementation of result_of that works with a pre-C++11 compiler. So, while I agree that I can use decltype or result_of<Mp(const MyClass&&)>::type in C++11, they do not do what I need for C++03. Several people have given the correct answer, which is that const rvalue arguments to functions are not part of the function type. This clarifies things for me and I will implement my pre-C++11 result_of such that it also discards those qualifiers.
const is stripped from function parameters. You can verify this using is_same.
void(int) == void(const int)
Mp(MyClass) == Mp(const MyClass)
result_of<Mp(MyClass)> == result_of<Mp(const MyClass)>
I think this is explained by [8.3.5.5]:
After producing the list of parameter types, any top-level
cv-qualifiers modifying a parameter type are deleted when forming the
function type. The resulting list of transformed parameter types and
the presence or absence of the ellipsis or a function parameter pack
is the function’s parameter-type-list. [ Note: This transformation
does not affect the types of the parameters. For example, int(*)(const
int p, decltype(p)*) and int(*)(int, const int*) are identical types.
— end note ]
You can work around it by defining your own result_of that does not (mis)use function types:
template <typename F, typename... ArgTypes>
struct my_result_of
{
using type = decltype(std::invoke(std::declval<F>(), std::declval<ArgTypes>()...));
};
This definition is really what the standard should have used.
In result_of_t<Mp(const MyClass)> you appear to be trying to ask what is the type of the result of invoking Mp with a const rvalue of type MyClass. A better way to ask that with result_of would be result_of_t<Mp(const MyClass&&)> but it's usually easier to just use decltype and forget that result_of ever existed. If you actually intended to ask the result with a const lvalue then that would be result_of_t<Mp(const MyClass&)>.
It is true that top-level const on function parameters has no meaning in a function declaration. When using result_of, therefore, it makes more sense to supply argument types as references to possibly-const types. This also makes the value category explicit, with no loss of expressivity. We can use the print_type trick to see what happens when we do this:
template <typename...> struct print_type; // forward declaration
print_type<std::result_of_t<Mp(const MyClass)>,
std::result_of_t<Mp(const MyClass&)>,
std::result_of_t<Mp(const MyClass&&)>,
std::result_of_t<Mp(MyClass)>,
std::result_of_t<Mp(MyClass&)>,
std::result_of_t<Mp(MyClass&&)>>{};
This prints:
error: invalid use of incomplete type 'struct print_type<int&&, const int&, const int&&, int&&, int&, int&&>'
So we can deduce:
std::result_of_t<Mp(const MyClass)> == int&&
std::result_of_t<Mp(const MyClass&)> == const int&
std::result_of_t<Mp(const MyClass&&)> == const int&&
std::result_of_t<Mp(MyClass)> == int&&
std::result_of_t<Mp(MyClass&)> == int&
std::result_of_t<Mp(MyClass&&)> == int&&
We can see that result_of_t<Mp(const MyClass)>, result_of_t<Mp(MyClass)>, and result_of_t<Mp(MyClass&&)> all mean the same thing. I would find it surprising if they didn't.
Note that when you use declval you are also providing argument types as references, as declval is declared to return a reference. Furthermore, all parameters to std::invoke are references.
As far as I know, I cannot declare an rvalue reference to void.
As an example, the following code is ill-formed:
void f(void &&v) { }
From [20.2.6/1] (function template declval) we have a declaration for declval that is:
template <class T>
add_rvalue_reference_t<T>
declval() noexcept;
Thus, declval<void> (let me say) would result in void &&, that I guessed it was ill-formed as well as in the previous example.
Anyway, the following minimal, working example compiles:
#include<utility>
int main() {
decltype(std::declval<void>())* ptr = nullptr;
}
Note that the following is true too:
static_assert(std::is_same<decltype(std::declval<void>()), void>::value, "!");
I would have expected it to be void&& as previously mentioned (or better, I was expecting it fails to compile).
Actually, it happens to be an rvalue reference for any other non-reference type.
As an example:
static_assert(std::is_same<decltype(std::declval<int>()), int&&>::value, "!");
Is declval<void> a valid expression or not? Is the code above legal?
Why does the behavior in case of void is different than with any other type? (For it wouldn't have worked otherwise could be an answer, if the code is legal).
If it's legal, where does the standard allow that? I've not been able to find the case.
Of course, the standard says:
The template parameter T of declval may be an incomplete type.
Anyway, here it would result in a non acceptable type (void&&) and it works around it discarding the rvalue reference.
add_rvalue_reference<T> only results in T&& if T is a referenceable type. So when T is void, the result is just void. This is also why you can add_rvalue_reference<int&&> and not get an error attempting to construct a reference to a reference. (Same with lvalue reference.)
Suppose I have a function that performs some side effect and then returns an answer:
int foo()
{
perform_some_side_effect();
return 42;
}
I want to bind foo to a function pointer, but I'm not interested in the answer, just the side effect:
void (*bar)() = foo;
However, this appears to be a type error:
error: invalid conversion from ‘int (*)()’ to ‘void (*)()’
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
On a side note, it works if I wrap the function pointer in a std::function:
std::function<void()> baz = foo;
How does std::function (apparently) manage to circumvent this restriction in the type system?
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
The reason is that the types are different, and the generated code at the place of call (through the function pointer) is different. Consider a calling convention where all arguments are written to the stack and space for the return value is also reserved in the stack. If the call goes through a void (*)() then no space will be reserved in the stack for the return value, but the function (unaware of how it is being called) will still write the 42 to the location where the caller should have reserved space.
How does std::function (apparently) manage to circumvent this restriction in the type system?
It does not. It creates a function object that wraps the call to the actual function. It will contain a member like:
void operator()() const {
foo();
}
Now when the compiler processes the call to foo it knows what it has to do to call a function that returns an int and it will do so according to the calling convention. Because the template does not return, it will just ignore the value --that was actually returned.
std::function need only be source compatible- that is, it can generate a new class which generates new caling code that ignores the result. The function pointer must be binary compatible and cannot do that job- void(*)() and int(*)() point to the exact same code.
You can think of std::function<> doing this for your particular case:
void __func_void()
{
foo();
}
It's actually a bit more complicated than that, but the point is that it generates template code together with type-erasure to not care about the specifics.
In addition to what others have been saying, the caller also need the return type to know what destructor it should invoke on the result (the return value may be a temporary).
Unfortunately it is not as easy as
auto (*bar)() = foo;
Although GCC and Clang accept this. I need to recheck the spec to see whether that's actually correct.
Update: The spec says
The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer or that a function declarator shall include a trailing-return-type.
This can be misleading when read fast, but this is implemented by GCC and clang to only apply to the toplevel declarator. In our case, this is a pointer declarator. The declarator nested in it is a function declarator. So just substitute auto for void and then the compiler will deduce the type for you.
By the way, you can always make this work manually, but it takes some trickery to make it work
template<typename FunctionType>
struct Params;
template<typename ...Params>
struct Params<void(Params...)> {
template<typename T>
using Identity = T;
template<typename R>
static Identity<R(Params...)> *get(R f(Params...)) {
return f;
}
};
// now it's easy
auto bar = Params<void()>::get(foo);
This is a follow-on question to
C++0x rvalue references and temporaries
In the previous question, I asked how this code should work:
void f(const std::string &); //less efficient
void f(std::string &&); //more efficient
void g(const char * arg)
{
f(arg);
}
It seems that the move overload should probably be called because of the implicit temporary, and this happens in GCC but not MSVC (or the EDG front-end used in MSVC's Intellisense).
What about this code?
void f(std::string &&); //NB: No const string & overload supplied
void g1(const char * arg)
{
f(arg);
}
void g2(const std::string & arg)
{
f(arg);
}
It seems that, based on the answers to my previous question that function g1 is legal (and is accepted by GCC 4.3-4.5, but not by MSVC). However, GCC and MSVC both reject g2 because of clause 13.3.3.1.4/3, which prohibits lvalues from binding to rvalue ref arguments. I understand the rationale behind this - it is explained in N2831 "Fixing a safety problem with rvalue references". I also think that GCC is probably implementing this clause as intended by the authors of that paper, because the original patch to GCC was written by one of the authors (Doug Gregor).
However, I don't this is quite intuitive. To me, (a) a const string & is conceptually closer to a string && than a const char *, and (b) the compiler could create a temporary string in g2, as if it were written like this:
void g2(const std::string & arg)
{
f(std::string(arg));
}
Indeed, sometimes the copy constructor is considered to be an implicit conversion operator. Syntactically, this is suggested by the form of a copy constructor, and the standard even mentions this specifically in clause 13.3.3.1.2/4, where the copy constructor for derived-base conversions is given a higher conversion rank than other user-defined conversions:
A conversion of an expression of class type to the same class type is given Exact Match rank, and a conversion
of an expression of class type to a base class of that type is given Conversion rank, in spite of the fact that
a copy/move constructor (i.e., a user-defined conversion function) is called for those cases.
(I assume this is used when passing a derived class to a function like void h(Base), which takes a base class by value.)
Motivation
My motivation for asking this is something like the question asked in How to reduce redundant code when adding new c++0x rvalue reference operator overloads ("How to reduce redundant code when adding new c++0x rvalue reference operator overloads").
If you have a function that accepts a number of potentially-moveable arguments, and would move them if it can (e.g. a factory function/constructor: Object create_object(string, vector<string>, string) or the like), and want to move or copy each argument as appropriate, you quickly start writing a lot of code.
If the argument types are movable, then one could just write one version that accepts the arguments by value, as above. But if the arguments are (legacy) non-movable-but-swappable classes a la C++03, and you can't change them, then writing rvalue reference overloads is more efficient.
So if lvalues did bind to rvalues via an implicit copy, then you could write just one overload like create_object(legacy_string &&, legacy_vector<legacy_string> &&, legacy_string &&) and it would more or less work like providing all the combinations of rvalue/lvalue reference overloads - actual arguments that were lvalues would get copied and then bound to the arguments, actual arguments that were rvalues would get directly bound.
Clarification/edit: I realize this is virtually identical to accepting arguments by value for movable types, like C++0x std::string and std::vector (save for the number of times the move constructor is conceptually invoked). However, it is not identical for copyable, but non-movable types, which includes all C++03 classes with explicitly-defined copy constructors. Consider this example:
class legacy_string { legacy_string(const legacy_string &); }; //defined in a header somewhere; not modifiable.
void f(legacy_string s1, legacy_string s2); //A *new* (C++0x) function that wants to move from its arguments where possible, and avoid copying
void g() //A C++0x function as well
{
legacy_string x(/*initialization*/);
legacy_string y(/*initialization*/);
f(std::move(x), std::move(y));
}
If g calls f, then x and y would be copied - I don't see how the compiler can move them. If f were instead declared as taking legacy_string && arguments, it could avoid those copies where the caller explicitly invoked std::move on the arguments. I don't see how these are equivalent.
Questions
My questions are then:
Is this a valid interpretation of the standard? It seems that it's not the conventional or intended one, at any rate.
Does it make intuitive sense?
Is there a problem with this idea that I"m not seeing? It seems like you could get copies being quietly created when that's not exactly expected, but that's the status quo in places in C++03 anyway. Also, it would make some overloads viable when they're currently not, but I don't see it being a problem in practice.
Is this a significant enough improvement that it would be worth making e.g. an experimental patch for GCC?
What about this code?
void f(std::string &&); //NB: No const string & overload supplied
void g2(const std::string & arg)
{
f(arg);
}
...However, GCC and MSVC both reject g2 because of clause 13.3.3.1.4/3, which prohibits lvalues from binding to rvalue ref arguments. I understand the rationale behind this - it is explained in N2831 "Fixing a safety problem with rvalue references". I also think that GCC is probably implementing this clause as intended by the authors of that paper, because the original patch to GCC was written by one of the authors (Doug Gregor)....
No, that's only half of the reason why both compilers reject your code. The other reason is that you can't initialize a reference to non-const with an expression referring to a const object. So, even before N2831 this didn't work. There is simply no need for a conversion because a string is a already a string. It seems you want to use string&& like string. Then, simply write your function f so that it takes a string by value. If you want the compiler to create a temporary copy of a const string lvalue just so you can invoke a function taking a string&&, there wouldn't be a difference between taking the string by value or by rref, would it?
N2831 has little to do with this scenario.
If you have a function that accepts a number of potentially-moveable arguments, and would move them if it can (e.g. a factory function/constructor: Object create_object(string, vector, string) or the like), and want to move or copy each argument as appropriate, you quickly start writing a lot of code.
Not really. Why would you want to write a lot of code? There is little reason to clutter all your code with const&/&& overloads. You can still use a single function with a mix of pass-by-value and pass-by-ref-to-const -- depending on what you want to do with the parameters. As for factories, the idea is to use perfect forwarding:
template<class T, class... Args>
unique_ptr<T> make_unique(Args&&... args)
{
T* ptr = new T(std::forward<Args>(args)...);
return unique_ptr<T>(ptr);
}
...and all is well. A special template argument deduction rule helps differentiating between lvalue and rvalue arguments and std::forward allows you to create expressions with the same "value-ness" as the actual arguments had. So, if you write something like this:
string foo();
int main() {
auto ups = make_unique<string>(foo());
}
the string that foo returned is automatically moved to the heap.
So if lvalues did bind to rvalues via an implicit copy, then you could write just one overload like create_object(legacy_string &&, legacy_vector &&, legacy_string &&) and it would more or less work like providing all the combinations of rvalue/lvalue reference overloads...
Well, and it would be pretty much equivalent to a function taking the parameters by value. No kidding.
Is this a significant enough improvement that it would be worth making e.g. an experimental patch for GCC?
There's no improvement.
I don't quite see your point in this question. If you have a class that is movable, then you just need a T version:
struct A {
T t;
A(T t):t(move(t)) { }
};
And if the class is traditional but has an efficient swap you can write the swap version or you can fallback to the const T& way
struct A {
T t;
A(T t) { swap(this->t, t); }
};
Regarding the swap version, I would rather go with the const T& way instead of that swap. The main advantage of the swap technique is exception safety and is to move the copy closer to the caller so that it can optimize away copies of temporaries. But what do you have to save if you are just constructing the object anyway? And if the constructor is small, the compiler can look into it and can optimize away copies too.
struct A {
T t;
A(T const& t):t(t) { }
};
To me, it doesn't seem right to automatically convert a string lvalue to a rvalue copy of itself just to bind to a rvalue reference. An rvalue reference says it binds to rvalue. But if you try binding to an lvalue of the same type it better fails. Introducing hidden copies to allow that doesn't sound right to me, because when people see a X&& and you pass a X lvalue, I bet most will expect that there is no copy, and that binding is directly, if it works at all. Better fail out straight away so the user can fix his/her code.