The boost::function FAQ item 3 specifically addresses the scenario I am interested in:
Why are there workarounds for void
returns? C++ allows them! Void returns
are permitted by the C++ standard, as
in this code snippet:
void f();
void g() { return f(); }
This is a valid usage of
boost::function because void returns
are not used. With void returns, we
would attempting to compile ill-formed
code similar to:
int f();
void g() { return f(); }
In essence, not using void returns
allows boost::function to swallow a
return value. This is consistent with
allowing the user to assign and invoke
functions and function objects with
parameters that don't exactly match.
Unfortunately, this doesn't work in VS2008:
int Foo();
std::tr1::function<void()> Bar = Foo;
This produces errors starting with:
c:\Program Files\Microsoft Visual Studio 9.0\VC\include\xxcallfun(7) : error C2562: 'std::tr1::_Callable_fun<_Ty>::_ApplyX' : 'void' function returning a value
Is this a failing of the VS2008 TR1 implementation? Does this work in VS2010? Does TR1 address this capability? How about C++0x?
I believe tr1 addresses this issue. N1836 (the latest tr1 draft) says:
A function object f of type F is
Callable for argument types T1, T2,
..., TN and a return type R, if, given
lvalues t1, t2, ..., tNoftypesT1, T2,
..., TN,respectively,INVOKE(f, t1, t2,
..., tN)is well-formed([3.3]) and, if R
is not void, convertible to R.
In your example R is void, and so the last part of the requirements for Callable (convertible to R) is ignored.
However it looks like C++0x (C++11) changes the rules. In C++11 Callable is defined as INVOKE(f, t1, t2, ..., tN, R) which is defined in [func.require] as requiring INVOKE(f, t1, t2, ..., tN) to be implicitly convertible to R, with no exception for when R is void. So in C++11, your example should fail.
Related
Is this not valid as C++14?
auto f = [](auto x, auto y = std::decay_t<decltype(x)>{}) { };
f(0);
I was expecting it to be roughly equivalent to
auto f = [](int x, int y) { };
f(0, int{});
Neither GCC 6.3 nor Clang 4.0 accepted my code.
http://ideone.com/b7b4SK GCC
http://ideone.com/EyLYaL Clang
Is it related to my lack of understanding of C++ template deduction phases? Does the 1400 pages long spec actually has an explicit answer to my question?
Update
To summarize, my problem can in fact be reduced to this piece of code (free of lambda, single parameter) and it is invalid under C++14 (thanks #BaummitAugen and #NirFriedman)
template <typename T>
void f(T x = 0) { }
int main() {
f();
}
The compilers are correct to reject your code, it is indeed not valid C++14.
In the standard (using N4141 here) we have
For a generic lambda, the closure type has a public inline function call
operator member template (14.5.2) whose template-parameter-list consists of one invented type template-
parameter for each occurrence of auto in the lambda’s parameter-declaration-clause, in order of appearance.
(5.1.2/4 [expr.prim.lambda]). So your call is equivalent to a call to some
template <class T1, class T2>
auto operator() (T1 x, T2 y = std::decay_t<decltype(x)>{});
Now
If a template parameter is used only in non-deduced
contexts and is not explicitly specified, template argument deduction fails.
(14.8.2/4 [temp.deduct.type]) and
The non-deduced contexts are:
[...]
- A template parameter used in the parameter type of a function parameter that has a default argument
that is being used in the call for which argument deduction is being done.
(14.8.2/5 [temp.deduct.type]) makes your call ill-formed.
I can't quote the spec, but I will quote cppreference which is an authoritative source and is often easier to read/follow. In particular, see http://en.cppreference.com/w/cpp/language/template_argument_deduction.
Non-deduced contexts
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction...
You probably are already aware that template parameters cannot always be deduced. Going down the list of entries, we see:
4) A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done:
Which gives the following example:
template<typename T, typename F>
void f(const std::vector<T>& v, const F& comp = std::less<T>());
std::vector<std::string> v(3);
f(v);
variadic lambdas are basically equivalent to function templates with a type template parameter substituted for each usage of auto, so this example (which does not compile) is equivalent to your example.
So basically, the second type cannot be deduced because it is a non-deduced context.
This answer could probably be improved by giving a very good example of why exactly it's been decided to make this a non-deduced context, since naively it seems like it's possible. My guess is that this is basically because a function template is just that, a template for creating function. Defaulted arguments in turn, essentially create multiple callable signatures for the same function. So you can't really deal with defaulting, until you have a function, but you can't have a function until you instantiate, which requires knowing the template parameters.
It's instructive to note that this simpler example has the same issues:
template<typename T, typename F>
void f(const std::vector<T>& v, const F& comp = int{});
So the dependence on the first template parameter actually has nothing to do with the issue.
In C++11, the two lines are equivalent. From what I see, the the advantage of the second syntax is that the return type is in class scope. Therefore, you can use both, nested types of the class directly and decltype expressions of non static members. Moreover, the function names line up nicely.
int foo(int bar);
auto foo(int bar) -> int;
The auto keyword is used here, which can also be used to automatically derive the type of local variables. However, I don't see the analogy here. In the function declaration syntax, nothing is derived. The return type is mentioned explicitly behind the arrow.
Personally, I would say that the syntax would be clearer without the auto keyword. Is there any intention behind this? Which?
The paper "Decltype (revision 5)", N1978 proposed the syntax for trailing-return-type (as they're now known). This was done to simplify defining function templates whose return type depends on an expression involving its arguments in chapter 3:
template <class T, class U> decltype((*(T*)0)+(*(U*)0)) add(T t, U u);
The expression (*(T*)0) is a hackish way to write an expression that has the type T and does not require T to be default
constructible. If the argument names were in scope, the above
declaration could be written as:
template <class T, class U> decltype(t+u) add(T t, U u);
Several syntaxes that move the return type expression after the
argument list are discussed in [Str02]. If the return type expression
comes before the argument list, parsing becomes difficult and name
lookup may be less intuitive; the argument names may have other uses
in an outer scope at the site of the function declaration.
We suggest reusing the auto keyword to express that the return type
is to follow after the argument list. The return type expression is
preceded by -> symbol, and comes after the argument list and
potential cv-qualifiers in member functions and the exception
specification:
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
The reference [Str02] is "Bjarne Stroustrup. Draft proposal for "typeof". C++ reflector message c++std-ext-5364, October 2002.", but I'm not sure if that's publicly available.
Adding this answer to complement #dyp's excellent answer.
Here's a real-world example from some code in my project that would be very difficult to write without the trailing return type:
template<class F, class... ArgTypes>
auto expected_from_code(F&& f, ArgTypes&& ...args)
-> expected_t<
typename std::enable_if<
!std::is_void<decltype(f(std::forward<ArgTypes>(args)...))>::value,
decltype(f(std::forward<ArgTypes>(args)...))>::type>
{
using expected = expected_t<decltype(f(std::forward<ArgTypes>(args)...))>;
try {
return expected { f(std::forward<ArgTypes>(args)...) };
}
catch(...) {
return expected { typename expected::exception_sentinel{} };
}
}
I noticed some strange results with std::is_convertible and std::is_assignable when std::function object and std::bind are involved.
I would assume that when these functions return true, the conversion can be made. Or am I missing something?
The following code prints different results on different compilers, and I would expect it to print 0 since these types cannot be assigned.
#include <type_traits>
#include <functional>
#include <iostream>
int main()
{
std::cout << std::is_convertible<std::function<void(int)>, std::function<void()>>::value << std::endl;
}
It prints 0 on the following compilers:
gcc 4.8 and gcc 4.9
clang 3.4 (but not the one from ubuntu 12.04)
It prints 1 on the following compilers:
gcc 4.7
VC++12 (VS2013)
clang 3.2
Is there any correct answer?
Are these bugs in compilers or am I messing with stuff that is compiler specific?
In C++11, std::function's constructor taking an arbitrary functor type is specified as (quoting N3337 §20.8.11.2.1 [func.wrap.func.con]/p7):
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R. The
copy constructor and destructor of A shall not throw exceptions.
Violation of a Requires clause (passing an f not Callable for argument types ArgTypes and return type R) is undefined behavior, so the library is free to do whatever it wants in that case. The library may take the constructor out of overload resolution, but it doesn't have to, and if it doesn't, then you will have issues with overload resolution and std::is_convertible- it will report that pretty much everything under the sun is convertible to std::function (including stuff like double!).
Hence, in LWG issue 2132, the standard was modified to require implementations to remove these constructors from overload resolution (via SFINAE or a similar technique) if the functor isn't Callable for the specified argument types and return type. It now reads:
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 Requires: F shall be CopyConstructible.
8 Remarks: These constructors shall not participate in overload
resolution unless f is Callable (20.9.11.2) for argument types
ArgTypes... and return type R.
So if your standard library implements this resolution, then std::is_convertible<std::function<void(int)>, std::function<void()>>::value is false. Otherwise, it's implementation-dependent.
I would assume that when these functions return true, the conversion can be made. Or am I missing something?
Type traits such as std::is_convertible, std::is_constructible, or std::is_assignable only considers the immediate context - i.e., whether there's a matching function signature that's accessible and not deleted. They don't check if the function's body would compile when instantiated.
I have some trouble understanding the need for std::result_of in C++0x. If I understood correctly, result_of is used to obtain the resulting type of invoking a function object with certain types of parameters. For example:
template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
return f(a);
}
I don't really see the difference with the following code:
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
return f(a);
}
or
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
return f(a);
}
The only problem I can see with these two solutions is that we need to either:
have an instance of the functor to use it in the expression passed to decltype.
know a defined constructor for the functor.
Am I right in thinking that the only difference between decltype and result_of is that the first one needs an expression whereas the second does not?
result_of was introduced in Boost, and then included in TR1, and finally in C++0x. Therefore result_of has an advantage that is backward-compatible (with a suitable library).
decltype is an entirely new thing in C++0x, does not restrict only to return type of a function, and is a language feature.
Anyway, on gcc 4.5, result_of is implemented in terms of decltype:
template<typename _Signature>
class result_of;
template<typename _Functor, typename... _ArgTypes>
struct result_of<_Functor(_ArgTypes...)>
{
typedef
decltype( std::declval<_Functor>()(std::declval<_ArgTypes>()...) )
type;
};
If you need the type of something that isn't something like a function call, std::result_of just doesn't apply. decltype() can give you the type of any expression.
If we restrict ourselves to just the different ways of determining the return type of a function call (between std::result_of_t<F(Args...)> and decltype(std::declval<F>()(std::declval<Args>()...)), then there is a difference.
std::result_of<F(Args...) is defined as:
If the expression
INVOKE (declval<Fn>(), declval<ArgTypes>()...) is well
formed when treated as an
unevaluated operand (Clause 5), the
member typedef type shall name the
type decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
otherwise, there shall be no member
type.
The difference between result_of<F(Args..)>::type and decltype(std::declval<F>()(std::declval<Args>()...) is all about that INVOKE. Using declval/decltype directly, in addition to being quite a bit longer to type, is only valid if F is directly callable (a function object type or a function or a function pointer). result_of additionally supports pointers to members functions and pointers to member data.
Initially, using declval/decltype guaranteed a SFINAE-friendly expression, whereas std::result_of could give you a hard error instead of a deduction failure. That has been corrected in C++14: std::result_of is now required to be SFINAE-friendly (thanks to this paper).
So on a conforming C++14 compiler, std::result_of_t<F(Args...)> is strictly superior. It's clearer, shorter, and correctly† supports more Fs‡ .
†Unless, that is, you're using it in a context where you don't want to allow pointers to members, so std::result_of_t would succeed in a case where you might want it to fail.
‡ With exceptions. While it supports pointers to members, result_of will not work if you try to instantiate an invalid type-id. These would include a function returning a function or taking abstract types by value. Ex.:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
The correct usage would've been result_of_t<F&()>, but that's a detail you don't have to remember with decltype.
I have this code:
#include <iostream>
#include <functional>
struct A
{
int operator()(int i) const {
std::cout << "F: " << i << std::endl;
return i + 1;
}
};
int main()
{
A a;
std::tr1::function<int(int)> f = std::tr1::ref(a);
std::cout << f(6) << std::endl;
}
The aim is to pass the functor object by a reference_wrapper, in a way to avoid useless copy costructor calls.
I expect the following output:
F: 6
7
It works correctly with GCC >= 4.4.0, Visual Studio 2008 and with boost by substituting std::tr1 namespace with boost. It only doesn't work with the new Visual Studio 2010 both Express Beta 2 and Release Candidate.
Are this new C++ features bugged in vs2010?
Or there is some mistake or misuse in the code?
I think i found the reason. This is what TR1 3.4/2 says about result_of<T(A1, A2, ..., AN)>::type, used in the determination of the return type of reference_wrapper<T>::operator():
The implementation may determine the type member via any means that produces the exact type of the expression f(t1, t2, ..., tN) for the given types. [Note: The intent is that implementations are permitted to use special compiler hooks —end note]
And then paragraph 3:
If F is not a function object defined by the standard library, and if either the implementation cannot determine the type of the expression f(t1, t2, ..., tN) or if the expression is ill-formed, the implementation shall use the following process to determine the type member:
If F is a possibly cv-qualified class type with no member named result_type or if typename F::result_type is not a type:
If N=0 (no arguments), type is void.
If N>0, type is typename F::template result<F(T1, T2,..., TN)>::type
The error message is an artefact of trying these fall-backs. Provide a typedef for result_type to int and it should work, i think. Notice that in C++0x, this is different. It does not rely on result_type or a result template, since it can use decltype.
If with <functional> it fails with MSVC10 in C++0x mode, it smells like a bug, i would say. But maybe someone else knows what's going on. It may (but is not guaranteed to) work with <tr1/functional> in C++0x mode if that header chooses to take the decltype way instead of ::result_type. I would typedef result_type - that way i think it should always work regardless of whether the tr1 header is used or the c++0x header.
Also notice that boost::tr1 says in its documentation that it does not support the function call operator (but it merely supports implicit conversions to T&).
I encounter a similar problem here :
Prevent unnecessary copies of C++ functor objects
To make it compile on MSVC10, I had to derive my function object from std::unary_function.