Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem creating template function alias with const value template arguments

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...) {
      |      ^~
like image 332
Battler Avatar asked Oct 27 '25 06:10

Battler


1 Answers

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.

like image 148
Jan Schultke Avatar answered Oct 28 '25 20:10

Jan Schultke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!