This is simplifed version of code that doesn't compile. I know that const value and value signature functions existing both are ambiguous, but I need two different functions based on constness of value template arguments. But I didn't expect to have problem taking somewhat alias of f1. It works with all const type references, but not with const value.
template<class... ARGS_T>
void f1(ARGS_T...) {
std::cout << (std::is_const_v<ARGS_T> || ...) << std::endl;
}
template<class... ARGS_T>
constexpr void(*f2)(ARGS_T...) = f1<ARGS_T...>;
class C {};
int main() {
f1<const int, const C>(1, C());
(*f2<const int, const C>)(3, C());
return 0;
}
Both versions of f1 are instantiated without problems and have different addresses, why I can't create two different pointers to them this way?
I am using g++ (Rev10, Built by MSYS2 project) 12.2.0 on Windows
Compilation errors:
C:/Alias/main.cpp: In instantiation of 'constexpr void (* const f2)(int, C)<const int, const C>':
C:/Alias/main.cpp:15:8: required from here
C:/Alias/main.cpp:9:17: error: no matches converting function 'f1' to type 'void (* const)(int, class C)'
9 | constexpr void(*f2)(ARGS_T...) = f1<ARGS_T...>;
| ^~
C:/Alias/main.cpp:4:6: note: candidate is: 'template<class ... ARGS_T> void f1(ARGS_T ...)'
4 | void f1(ARGS_T...) {
| ^~
This looks to be a compiler bug in GCC, which is related to const in function parameters. Firstly, note that const in function parameters is not part of the function type:
After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type.
- [dcl.fct] p5
This means that void(int) and void(const int) are the same type. The same applies to the function pointer types void(*)(int) and void(*)(const int). All major compilers accept the following code, as they should:
void fi(int);
void fci(const int);
void(*pfi)(int) = &fi; // OK
void(*pfci)(int) = &fci; // OK
void(*pcfi)(const int) = &fi; // OK
void(*pcfci)(const int) = &fci; // OK
For some reason, GCC doesn't correctly perform this type adjustment when dealing with variadic templated function types:
// note: using a single T instead of ARGS_T... works
template<class... ARGS_T>
void f(ARGS_T...) {}
void(*pfi)(int) = &f<int>; // OK
void(*pfci)(int) = &f<const int>; // error
void(*pcfi)(const int) = &f<int>; // OK
void(*pcfci)(const int) = &f<const int>; // error
See Compiler Explorer.
Clang and MSVC compile this code, but GCC doesn't. The type of f<const int> is void(const int) which is the same type as void(int), so this code should compile, just like the first example.
Note: I have submitted a GCC bug report. See GCC Bug 111662.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With