std::function, literal types and templates - c++

I'm working on C++17 project which among others have these definitions (in my namespace, of course):
using CppFunction = std::function<int(StatePtr&)>;
template<typename T>
using CppMethod = std::function<int(T*, StatePtr&)>;
Now I declare some functions:
template<typename... Targs, typename F>
constexpr CppFunction CppFunctionNative(F func);
template<typename... Targs, typename F, typename T = (deducing class from F here) >
constexpr CppMethod<T> CppMethodNative(F func);
To my surprise, first declaration cause compiler error Constexpr function's return type is not a literal type, but second works just fine.
Why does this happen? Is it related to the fact that second function's return type is template?
UPD: simplified standalone example:
#include <functional>
using CppFunction = std::function<int(int&)>;
template<typename T>
using CppMethod = std::function<int(T*, int&)>;
// Clang will complain
template<typename F>
constexpr CppFunction CppFunctionNative(F func) {};
// Clang will not complain
template<typename F, typename T = /*(deducing class from F here)*/char >
constexpr CppMethod<T> CppMethodNative(F func) {};
// main() function doesn't matter
int main() {
CppFunctionNative(0);
CppMethodNative(0);
return 0;
};
Interestingly enough, OnlineGDB and offline GCC 8.3.0 doesn't complain about this, but my Clang 8 does.

To my surprise, first declaration cause compiler error Constexpr function's return type is not a literal type, but second works just fine.
Why does this happen? Is it related to the fact that second function's return type is template?
Yes. In the first case, the compiler can prove that that specific specialization of std::function is not a literal type.
In the second case, it must know T before it knows if the specific specialization of std::function is a literal type.
template<class T>
struct example {
virtual T get() const {return {};}
~example() {}
};
template<>
struct example<int> {};
#if 0
template<class F>
constexpr example<double> test( F ) { return {}; }
#endif
template<class T, class F>
constexpr example<T> test2( F ) { return {}; }
Live example
test is illegal; test2 is fine. In fact, test2<int>( 3.14 ) is a legal constexpr call.
Now, std::function has no such specialization, but that is not something the compiler is required to prove; doing so in general requires solving the halting problem, which is something C++ standard tries to avoid asking compilers to do.
As mentioned by #MaxLanghof, this kind of error results in an "ill-formed, no diagnostic required" program. The compiler is not forced to detect that your constexpr function cannot be constexpr, but if you do that the compiler is free to do anything, including generate an error message (or worse things).
So GCC is not wrong to omit the error, and clang is not wrong to emit an error. Clang's error emission is, in a sense, a higher QoI than gcc's omission.

Edit: Yakk's answer is more complete - one has to of course consider the theoretical possibility of std::function specializations!
constexpr means "there is at least one set of arguments for which this function produces a constant expression". If no such arguments exist, the program is ill-formed, no diagnostic required. This means it is up to the compiler whether it completely ignores this issue, whether it only complains at instantiation-time or whether it already barks at the declaration.
clang is evidently smart/eager enough to realize that a function template with a non-literal return type can never be constexpr. gcc does not seem to bother checking this - it's not required to. Your program is still wrong though - std::function is not a literal type and can thus never be returned from a constexpr function.

Related

Can a compiler decide to ignore a missing typename on dependent type where it is still required by C++20?

The following code compiles with MSVC but fails with GCC and Clang for missing typename before a dependent type:
struct Foo { struct value{ }; };
struct Bar { int value; };
template<typename T>
constexpr size_t SIZE = sizeof(T::value); // missing typename here, for Foo
constexpr size_t s1 = SIZE<Foo>; // missing typename before dependent type above
constexpr size_t s2 = SIZE<Bar>;
MSVC approach, not requiring typename for sizeof, seems reasonable, as sizeof works on both types and variables. On the other hand GCC and Clang seem to play by the book, as this is one of those cases where you still need typename even in C++20, when the context cannot reveal to the compiler whether it is going to meet a type or a variable.
The question is whether MSVC is allowed to be permissive here, that is, if the compiler can perform the required operation correctly without the typename, is it allowed to do so? Or does it contradict the specification?
The difference between the approach of MSVC vs. Clang and GCC comes to an actual difference in the following code, which compiles by all three compilers but behaves differently:
template<typename T> concept A1 = sizeof(typename T::value) > 0;
template<typename T> concept A2 = sizeof(T::value) > 0;
struct Foo { struct value{ }; };
constexpr bool v1 = A1<Foo>; // true with all
constexpr bool v2 = A2<Foo>; // true with MSVC, false with GCC and Clang
In the above code, GCC and Clang see the omission of typename in A2 as illegal and thus fail the concept, this is not compilation error but rather having the concept getting the boolean value false ([temp.constr.atomic]).
C++20 spec ([temp.res.general]) lists the places where typename is not required for assuming a qualified-id is a type. The sizeof operator is not in that list, so it seems that it should require typename for a template dependent-type. On the other hand, sizeof doesn't appear in the example as ill-formed, no diagnostic required for missing typename (not being in the example does not say anything, but still keeps the question, in a way).
Why sizeof may allow inferring proper operation without adding typename? Mainly because it shouldn't really care if this is a type or a variable. And the spec does not say specifically that this is ill-formed. If it does say that it is ill-formed, then a pointer to this should be the answer, which will probably make MSVC behavior a defect.
As a side note, that does not answer the question, one can make all three compilers happy with the following code:
template<typename T>
constexpr size_t SIZE = sizeof(T::value);
template<typename T> requires requires { typename T::value; }
constexpr size_t SIZE<T> = sizeof(typename T::value);
And for the concept:
template<typename T> concept A =
sizeof(T::value) > 0 ||
sizeof(typename T::value) > 0;
The standard is very indirect about this point, but it’s pretty clear that MSVC is not conforming here. (In the non-SFINAE/concept case, it would be allowed to issue merely a warning (“operand of sizeof considered a type despite missing ‘typename’”) and continue, but that’s not really the point.)
Note that even in the trivial case of
struct X;
int y=X;
the error is that X can’t be interpreted as an unqualified-id because it is not “suitably declared” ([expr.prim.id.unqual]/1). In a template the grammatical interpretation is fixed by the presence of absence of typename, despite the fact that qualified-ids are thereby produced without knowing whether their terminal names are so suitably declared; we evidently must reject them if eventually they are found wanting in that regard.

Different SFINAE behavior of `std::tuple_size_v` on different compilers

Consider this code:
#include <tuple>
#include <type_traits>
#include <iostream>
template <typename T, typename = void> struct is_tuple_like : std::false_type {};
template <typename T> struct is_tuple_like<T, decltype(std::tuple_size_v<T>, void())> : std::true_type {};
int main()
{
std::cout << is_tuple_like<std::string>::value << '\n';
}
Run on gcc.godbolt.org
On GCC 10.2 and MSVC 19.28 it causes a hard error, along the lines of:
error: incomplete type 'std::tuple_size<...>' used in nested name specifier
On Clang 11.0.1, on the other hand, it compiles and prints 1, with both libstdc++ and libc++.
Which compiler is correct here?
Notice that Clang prints 1 and not 0, meaning it doesn't treat std::tuple_size<std::string>::value (the initializer of tuple_size_v) as a soft error, but instead chooses to disregard it completely!
Which makes sense in a way, since if tuple_size_v is defined as template <typename T> inline constexpr size_t tuple_size_v = ..., the type decltype(tuple_size_v<...>) doesn't depend on the template parameter, and is always size_t.
I guess the question boils down to whether the initializer of tuple_size_v is required to be instantiated here, even though it's not strictly necessary.
I know that I can fix it by replacing std::tuple_size_v<...> with std::tuple_size<...>::value, then it prints 0 on all three compilers.
I think Clang has this right.
The rule from [temp.inst]/7 is:
Unless a variable template specialization is a declared specialization, the variable template specialization is implicitly instantiated when it is referenced in a context that requires a variable definition to exist or if the existence of the definition affects the semantics of the program.
This program doesn't require the definition of std::tuple_size_v<std::string>, only the declaration. And the declaration:
template <typename T>
inline constexpr size_t tuple_size_v = tuple_size<T>::value;
Is enough to evaluate the expression in the partial specialization. decltype(std::tuple_size_v<T>, void()) doesn't depend on the value here at all, for any size_t, that's a valid expression of type void.
Were we dealing with a function template instead of a variable template:
template <typename T>
constexpr size_t tuple_size_v() { return tuple_size<T>::value; }
It's perhaps more clear that we don't need the definition, just the declaration, and both gcc and msvc accept this alternate formulation (indeed, gcc even warns on it being pointless): example.
Later, in [temp.inst]/8, we have:
The existence of a definition of a variable or function is considered to affect the semantics of the program if the variable or function is needed for constant evaluation by an expression ([expr.const]), even if constant evaluation of the expression is not required or if constant expression evaluation does not use the definition.
But that is not the case here: we don't need the variable for constant evaluation.

SFINAE not working inside decltype() when attempting to disable a no-args member function

I have distilled the issue down to the following class which is attempting to use std::enable_if to disable a member function:
#include <type_traits>
int foo(int& x) {
return x;
}
template<bool enable>
struct A {
int x;
template<bool dummy=true,
typename Enabler = typename std::enable_if<dummy && enable>::type>
auto disabled_method() const -> decltype(foo(x)) {
return foo(x);
}
};
int main() {
A<false> x;
}
There is a type error in the expression decltype(foo(x)), even though the function should be disabled by the enable_if!
Note that it is particular to occuring in the return type of the function. For example, if we move the decltype(foo(x)) to the body of the function, SFINAE will work fine:
template<bool dummy=true,
typename Enabler = typename std::enable_if<dummy && enable>::type>
auto disabled_method() const -> int {
decltype(foo((X)x)) local;
return foo(x);
}
(Same for using decltype(foo((X)x)) as an argument type)
Likewise, it will correctly perform SFINAE if I declare it as
template<bool dummy=true,
typename X = const int,
typename Enabler = typename std::enable_if<dummy && enable>::type>
auto disabled_method() const -> decltype(foo((X)x)) {
return foo(x);
}
But using decltype(foo((const int)x)), it will error out, despite X being equal to const int above. This seems to indicate that introducing the extra cast to the template parameter X causes it to delay the substitution.
But the dummy and Enabler template pattern up above is supposed to do that anyways?
Why is this happening?
This has nothing to do with "immediate context".
In general, errors in nondependent constructs render the program ill-formed NDR (no diagnostic required), see [temp.res]/8. Implementations have broad leeway to diagnose - or not diagnose - such problems.
In your case, foo(x) doesn't depend on a template parameter, and is always ill-formed; implementations are therefore free to diagnose it even if A is never instantiated.
The return type is a part of the SFINAE process, this is why you can also include the std::enable_if as a part of the return type. But SFINAE only works if there is an error in the immediate context, the foo(x) however is not a part of the immediate template context, therefore the compiler throws an error.
For example, if you change the code to be the following
template<bool dummy=true>
std::enable_if_t<dummy && enable, decltype(foo(x))> disabled_method()
const {
return foo(x);
}
Then the enable_if works, because not the decltype(foo(x)) is a part of the enable_if itself and outside the immediate context where x is non-const
Take a look at this question and its answer for more information about what the immediate context is What exactly is the "immediate context" mentioned in the C++11 Standard for which SFINAE applies?
For your convenience, a quote from the linked question's answer that explains what the immediate context is
If you consider all the templates and implicitly-defined functions that are needed to determine the result of the template argument substitution, and imagine they are generated first, before substitution starts, then any errors occurring in that first step are not in the immediate context, and result in hard errors.
In your example, the return type is needed to determine the result of the template argument substitution and is independent of the substitution process, hence it results in a hard error.
Also in such cases, I usually find it easier to leave out the return type entirely, and let the compiler deduce it. It's much easier to work with.

std::function overload ambiguity [duplicate]

Given the following code, what is the reason behind the ambiguity? Can I circumvent it or will I have to keep the (annoying) explicit casts?
#include <functional>
using namespace std;
int a(const function<int ()>& f)
{
return f();
}
int a(const function<int (int)>& f)
{
return f(0);
}
int x() { return 22; }
int y(int) { return 44; }
int main()
{
a(x); // Call is ambiguous.
a(y); // Call is ambiguous.
a((function<int ()>)x); // Works.
a((function<int (int)>)y); // Works.
return 0;
}
Interestingly, if I comment out the a() function with the function<int ()> parameter and call a(x) in my main, the compilation correctly fails because of the type mismatch between x and the argument function<int (int)> of the only a() function available. If the compiler fails in that case, why would there be any ambiguity when the two a() functions are present?
I've tried with VS2010 and g++ v. 4.5. Both give me the exact same ambiguity.
The problem is that both function<int()> and function<int(int)> are constructible from the same function. This is what the constructor declaration of std::function looks like in VS2010:
template<class _Fx>
function(_Fx _Func, typename _Not_integral<!_Is_integral<_Fx>::value, int>::_Type = 0);
Ignoring the SFINAE part, it is constructible from pretty much anything.
std::/boost::function employ a technique called type erasure, to allow arbitary objects/functions to be passed in, so long they satisfy the signature when being called. One drawback from that is, that you get an error in the deepest part of the implementation (where the saved function is being called) when supplying an object which can't be called like the signature wants it to, instead of in the constructor.
The problem can be illustrated with this little class:
template<class Signature>
class myfunc{
public:
template<class Func>
myfunc(Func a_func){
// ...
}
};
Now, when the compiler searches for valid functions for the overload set, it tries to convert the arguments if no perfect fitting function exists. The conversion can happen through the constructor of the parameter of the function, or through a conversion operator of the argument given to the function. In our case, it's the former.
The compiler tries the first overload of a. To make it viable, it needs to make a conversion. To convert a int(*)() to a myfunc<int()>, it tries the constructor of myfunc. Being a template that takes anything, the conversion naturally succeeds.
Now it tries the same with the second overload. The constructor still being the same and still taking anything given to it, the conversion works too.
Being left with 2 functions in the overload set, the compiler is a sad panda and doesn't know what to do, so it simply says the call is ambigious.
So in the end, the Signature part of the template does belong to the type when making declarations/definitions, but doesn't when you want to construct an object.
Edit:
With all my attention on answering the title-question, I totally forgot about your second question. :(
Can I circumvent it or will I have to keep the (annoying) explicit casts?
Afaik, you have 3 options.
Keep the cast
Make a function object of the appropriate type and pass that
function<int()> fx = x;
function<int(int)> fy = y;
a(fx);
a(fy);
Hide the tedious casting in a function and use TMP to get the right signature
The TMP (template metaprogramming) version is quite verbose and with boilerplate code, but it hides the casting from the client. An example version can be found here, which relies on the get_signature metafunction that is partially specialized on function pointer types (and provides a nice example how pattern matching can work in C++):
template<class F>
struct get_signature;
template<class R>
struct get_signature<R(*)()>{
typedef R type();
};
template<class R, class A1>
struct get_signature<R(*)(A1)>{
typedef R type(A1);
};
Of course, this needs to be extended for the number of arguments you want to support, but that is done once and then buried in a "get_signature.h" header. :)
Another option I consider but immediatly discarded was SFINAE, which would introduce even more boilerplate code than the TMP version.
So, yeah, that are the options that I know of. Hope one of them works for you. :)
I've seen this question come up one too many times. libc++ now compiles this code without ambiguity (as a conforming extension).
Overdue Update
This "extension" proved sufficiently popular that it was standardized in C++14 (though I was not personally responsible for getting that job done).
In hindsight, I did not get this extension exactly correct. Earlier this month (2015-05-09) the committee voted in LWG issue 2420 which effectively changes the definition of Callable so that if the std::function has a void return type it will ignore the return type of the wrapped functor, but still otherwise consider it Callable if everything else matches up, instead of considering it not Callable.
This post-C++14 tweak does not impact this particular example since the return types involved are consistently int.
Here's an example of how to wrap std::function in a class that checks invokability of its constructor parameters:
template<typename> struct check_function;
template<typename R, typename... Args>
struct check_function<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_same<R, void>::value
|| std::is_convertible<
decltype(std::declval<T>()(std::declval<Args>()...)),
R>::value>::type>
check_function(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};
Use like this:
int a(check_function<int ()> f) { return f(); }
int a(check_function<int (int)> f) { return f(0); }
int x() { return 22; }
int y(int) { return 44; }
int main() {
a(x);
a(y);
}
Note that this isn't quite the same as overloading on function signature, as it treats convertible argument (and return) types as equivalent. For exact overloading, this should work:
template<typename> struct check_function_exact;
template<typename R, typename... Args>
struct check_function_exact<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_convertible<T, R(*)(Args...)>::value>::type>
check_function_exact(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};
std::function<T> has a conversion ctor that takes an arbitrary type (i.e., something other than a T). Sure, in this case, that ctor would result in a type mismatch error, but the compiler doesn't get that far -- the call is ambiguous simply because the ctor exists.

Isn't the template argument (the signature) of std::function part of its type?

Given the following code, what is the reason behind the ambiguity? Can I circumvent it or will I have to keep the (annoying) explicit casts?
#include <functional>
using namespace std;
int a(const function<int ()>& f)
{
return f();
}
int a(const function<int (int)>& f)
{
return f(0);
}
int x() { return 22; }
int y(int) { return 44; }
int main()
{
a(x); // Call is ambiguous.
a(y); // Call is ambiguous.
a((function<int ()>)x); // Works.
a((function<int (int)>)y); // Works.
return 0;
}
Interestingly, if I comment out the a() function with the function<int ()> parameter and call a(x) in my main, the compilation correctly fails because of the type mismatch between x and the argument function<int (int)> of the only a() function available. If the compiler fails in that case, why would there be any ambiguity when the two a() functions are present?
I've tried with VS2010 and g++ v. 4.5. Both give me the exact same ambiguity.
The problem is that both function<int()> and function<int(int)> are constructible from the same function. This is what the constructor declaration of std::function looks like in VS2010:
template<class _Fx>
function(_Fx _Func, typename _Not_integral<!_Is_integral<_Fx>::value, int>::_Type = 0);
Ignoring the SFINAE part, it is constructible from pretty much anything.
std::/boost::function employ a technique called type erasure, to allow arbitary objects/functions to be passed in, so long they satisfy the signature when being called. One drawback from that is, that you get an error in the deepest part of the implementation (where the saved function is being called) when supplying an object which can't be called like the signature wants it to, instead of in the constructor.
The problem can be illustrated with this little class:
template<class Signature>
class myfunc{
public:
template<class Func>
myfunc(Func a_func){
// ...
}
};
Now, when the compiler searches for valid functions for the overload set, it tries to convert the arguments if no perfect fitting function exists. The conversion can happen through the constructor of the parameter of the function, or through a conversion operator of the argument given to the function. In our case, it's the former.
The compiler tries the first overload of a. To make it viable, it needs to make a conversion. To convert a int(*)() to a myfunc<int()>, it tries the constructor of myfunc. Being a template that takes anything, the conversion naturally succeeds.
Now it tries the same with the second overload. The constructor still being the same and still taking anything given to it, the conversion works too.
Being left with 2 functions in the overload set, the compiler is a sad panda and doesn't know what to do, so it simply says the call is ambigious.
So in the end, the Signature part of the template does belong to the type when making declarations/definitions, but doesn't when you want to construct an object.
Edit:
With all my attention on answering the title-question, I totally forgot about your second question. :(
Can I circumvent it or will I have to keep the (annoying) explicit casts?
Afaik, you have 3 options.
Keep the cast
Make a function object of the appropriate type and pass that
function<int()> fx = x;
function<int(int)> fy = y;
a(fx);
a(fy);
Hide the tedious casting in a function and use TMP to get the right signature
The TMP (template metaprogramming) version is quite verbose and with boilerplate code, but it hides the casting from the client. An example version can be found here, which relies on the get_signature metafunction that is partially specialized on function pointer types (and provides a nice example how pattern matching can work in C++):
template<class F>
struct get_signature;
template<class R>
struct get_signature<R(*)()>{
typedef R type();
};
template<class R, class A1>
struct get_signature<R(*)(A1)>{
typedef R type(A1);
};
Of course, this needs to be extended for the number of arguments you want to support, but that is done once and then buried in a "get_signature.h" header. :)
Another option I consider but immediatly discarded was SFINAE, which would introduce even more boilerplate code than the TMP version.
So, yeah, that are the options that I know of. Hope one of them works for you. :)
I've seen this question come up one too many times. libc++ now compiles this code without ambiguity (as a conforming extension).
Overdue Update
This "extension" proved sufficiently popular that it was standardized in C++14 (though I was not personally responsible for getting that job done).
In hindsight, I did not get this extension exactly correct. Earlier this month (2015-05-09) the committee voted in LWG issue 2420 which effectively changes the definition of Callable so that if the std::function has a void return type it will ignore the return type of the wrapped functor, but still otherwise consider it Callable if everything else matches up, instead of considering it not Callable.
This post-C++14 tweak does not impact this particular example since the return types involved are consistently int.
Here's an example of how to wrap std::function in a class that checks invokability of its constructor parameters:
template<typename> struct check_function;
template<typename R, typename... Args>
struct check_function<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_same<R, void>::value
|| std::is_convertible<
decltype(std::declval<T>()(std::declval<Args>()...)),
R>::value>::type>
check_function(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};
Use like this:
int a(check_function<int ()> f) { return f(); }
int a(check_function<int (int)> f) { return f(0); }
int x() { return 22; }
int y(int) { return 44; }
int main() {
a(x);
a(y);
}
Note that this isn't quite the same as overloading on function signature, as it treats convertible argument (and return) types as equivalent. For exact overloading, this should work:
template<typename> struct check_function_exact;
template<typename R, typename... Args>
struct check_function_exact<R(Args...)>: public std::function<R(Args...)> {
template<typename T,
class = typename std::enable_if<
std::is_convertible<T, R(*)(Args...)>::value>::type>
check_function_exact(T &&t): std::function<R(Args...)>(std::forward<T>(t)) { }
};
std::function<T> has a conversion ctor that takes an arbitrary type (i.e., something other than a T). Sure, in this case, that ctor would result in a type mismatch error, but the compiler doesn't get that far -- the call is ambiguous simply because the ctor exists.