gcc 使用常量值模板参数创建模板函数别名时出错

46qrfjad  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(129)

这是简化版本的代码,不编译。我知道const value和value signature函数都是不明确的,但我需要两个不同的函数,基于值模板参数的constness。但我没想到会有问题采取一些别名的f1。它适用于所有const类型引用,但不适用于const值。

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;
}

两个版本的f1都示例化了,没有问题,并且有不同的地址,为什么我不能用这种方式创建两个不同的指向它们的指针?
我在Windows上使用g++(Rev10,Built by MSYS2 project)12.2.0
编译错误:

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...) {
      |      ^~
mjqavswn

mjqavswn1#

这看起来是GCC中的编译器错误,与函数参数中的const有关。首先,注意函数参数中的const不是函数类型的一部分:
在生成参数类型列表之后,任何修改参数类型的顶级 * cv-限定符 * 在形成函数类型时被删除。

  • [dcl.fct] p5
    这意味着void(int)void(const int)是相同的类型。这同样适用于函数指针类型void(*)(int)void(*)(const int)。所有主要的编译器都接受以下代码,因为它们应该这样做:
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

由于某些原因,GCC在处理可变模板函数类型时不能正确执行这种类型调整:

// 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

Clang和MSVC可以编译这些代码,但GCC不能。f<const int>的类型是void(const int),它与void(int)的类型相同,所以这段代码应该可以编译,就像第一个例子一样。

相关问题