使用常量值模板参数创建模板函数别名时出现问题

Problem creating template function alias with const value template arguments

提问人:Battler 提问时间:10/2/2023 最后编辑:Battler 更新时间:10/2/2023 访问量:116

问:

这是不编译的代码的简单版本。我知道存在的常量值和值签名函数都是模棱两可的,但我需要两个基于值模板参数恒常性的不同函数。但我没想到在取 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,由 MSYS2 项目构建)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...) {
      |      ^~
C++ 模板 GCC language-lawyer 编译器-bug

评论

0赞 Quimby 10/2/2023
请添加编译错误。

答:

2赞 Jan Schultke 10/2/2023 #1

这看起来像是 GCC 中的编译器错误,与函数参数有关。首先,请注意,函数参数不是函数类型的一部分:constconst

生成参数类型列表后,在形成函数类型时,将删除任何修改参数类型的顶级 cv 限定符

- [dcl.fct] 第 5 页

这意味着 和 是同一类型。这同样适用于函数指针类型和 。所有主要编译器都接受以下代码,因为它们应该接受: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)


注意:我已经提交了 GCC 错误报告。请参阅 GCC Bug 111662