Nontype template parameter generated with decltype function for function
I want to replace the signature signature with decltype and found out that it doesn't compile with most compilers. Is this a new feature, or perhaps unspecified behavior?
#include <iostream>
template <typename T, T nontype>
struct CL {
void call() { nontype(123); }
};
void f(int n) {
std::cout << n << std::endl;
}
CL<void(*)(int), f> cl7;
using df = decltype(f);
CL<df, f> cl8; // << error
int main() {
cl8.call();
}
so (not really sure about the compiler versions):
clang - 3.4 http://rextester.com/UOIV91915
compiles, runs, produces output
g ++ 4.9+ http://coliru.stacked-crooked.com/a/dbec1e202c48fd81
main.cpp:14:9: error: 'void(int)' is not a valid type for a template non-type parameter
CL<df, f> cl8; // << error
^
main.cpp:14:14: error: invalid type in declaration before ';' token
CL<df, f> cl8; // << error
^
main.cpp: In function 'int main()':
main.cpp:17:6: error: request for member 'call' in 'cl8', which is of non-class type 'int'
cl8.call();
Visual Studio 2013 Update 4
fatal error C1001: An internal error has occurred in the compiler.
source to share
Non-standard template parameters cannot be of function type. They can have a pointer to a function type, and there is a paragraph in the standard that somehow means your code is correct - [temp.param] / 8:
A non-standard template parameter of type "array
T
" or "function returnT
" is configured as "pointer toT
" or "pointer to function returnsT
", respectively.
However, it is unclear if this is done after replacing the template or before it, which is covered in this defect report . It's easy to fix it just to write
using df = decltype(&f);
Demo .
Why does it work using df = decltype((f));
?
[dcl.type.simple] / 4:
For an expression, the
e
type denoted by a symboldecltype(e)
is defined as follows:
- if
e
is an unparenthesized id-expression or unbound class member access (5.2.5),decltype(e)
is the type of object namede
. If no such object is present, or if e names a set of overloaded functions, the program is ill-formed;- otherwise, if
e
is the value of x,decltype(e)
isT&&
whereT
is the typee
;- otherwise , if
e
is an lvalue,decltype(e)
isT&
whereT
is the typee
;- otherwise, it
decltype(e)
is the typee
.
(f)
is enclosed in parentheses and an lvalue, so it decltype((f))
is an lvalue reference to f
the function type - void(&)(int)
. Template parameters can be referenced to the function type, so it works. However, since this fact is rather controversial (and not so well known), it decltype(&f)
should be less annoying in your code.
source to share