This answer has a code snippet like this :
template<class T, class F>
auto f(std::vector<T> v, F fun)
-> decltype( bool( fun(v[0] ) ), void() )
{
// ...
}
It really compiles and work (at least on Ideone).
So, how is the type deduced in this case?
Is next line really allowed by c++11 standard?
decltype( bool( fun(v[0] ) ), void() )
I took a quick look, and it doesn't look valid. Is ideone wrong in this case?
All examples in the c++11 standard are such that they all got only one type in the decltype :
struct A {
char g();
template<class T> auto f(T t) -> decltype(t + g())
{ return t + g(); }
};
another example :
void f3() {
float x, &r = x;
[=] {
decltype(x) y1;
decltype((x)) y2 = y1;
decltype(r) r1 = y1;
decltype((r)) r2 = y2;
};
and another
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = i;
decltype(i) x2;
decltype(a->x) x3;
decltype((a->x)) x4 = x3;
They all got only one parameter in decltype. How come the top code take two parameters (separated by a comma)?
I created another example (which fails to compile) :
#include <vector>
#include <iostream>
template<class T, class F>
auto f(std::vector<T> v, F fun) -> decltype(bool(fun(v[0])), void())
{
// ...
(void)v;(void)fun;
return fun(v.size());
}
void ops(int)
{
}
int main(){
std::vector<int> v;
f(v, [](int){ return true; });
f(v,ops);
}
Even if the line f(v,ops);
is removed, the return type of the f
template function is evaluated to void.
decltype( bool( fun(v[0] ) ), void() )
uses the comma operator.Breaking it down,
is composed of two expressions; the first
is evaluated1 and discarded, giving the overall expression the value
which is a value2 of type
void
.decltype
then yields the type of the expression, which as above isvoid
.The reason to use the comma operator here is to ensure that the whole expression is only valid if the first subexpression is valid; this is because it is being used in SFINAE to exclude it from substitution consideration if the first subexpression is invalid.
This works because although
decltype
looks syntactically like a function, it is actually a language construct that (likesizeof
) is defined to take a single argument. It might be clearer to parenthesise the comma-operator argument:Notes
bool( fun(v[0] ) )
is not actually evaluated, because we're in a non-evaluated context (decltype
, similar tosizeof
). What matters here is that it would be evaluated if the expression as a whole was evaluated, so that if the subexpression is invalid then the whole expression is invalid.void()
isn't really a value, but it behaves like a value in the context of the comma operator anddecltype
.