为什么对指针的参数包进行常量限定是错误的?

Why is it an error to const-qualify a parameter pack of pointers?

当实现接受指向 Ts... 的指针参数包的函数时,为什么我不能 const 限定指针,就像使用常规参数一样?

我在最新的 GCC 和 Clang 上遇到不匹配的签名错误,我不明白为什么,因为指针 const 只是一个实现细节(因此它对于常规参数是合法的)。

template<typename... Ts>
class C
{
    void f(int*);
    void g(Ts*...);
};

template<typename... Ts>
void C<Ts...>::f(int* const) {} // Legal

template<typename... Ts>
void C<Ts...>::g(Ts* const...) {} // Compiler error

我收到这个错误:

prog.cc:12:16: error: out-of-line definition of 'g' does not match any declaration in 'C<Ts...>'
void C<Ts...>::g(Ts* const...) {}
               ^
1 error generated.

您还可以看到代码和错误 here

我将把它归结为两个编译器错误(经过测试的 Clang 和 GCC)。我知道这是一个大胆的断言,但是 [dcl.fct]/5 说,强调我的:

A single name can be used for several different functions in a single scope; this is function overloading. All declarations for a function shall agree exactly in both the return type and the parameter-type-list. The type of a function is determined using the following rules. The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”. After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function's parameter-type-list. [ Note: This transformation does not affect the types of the parameters. For example, int()(const int p, decltype(p)) and int()(int, const int) are identical types.  — end note ]

这对我来说很清楚,两个成员(f g)的声明匹配 out-of-class 定义,使您的程序有效。所以 Clang 和 GCC 应该接受它。

3 年后......仅供参考......

MSVC 19.28.29337(使用 Visual Studio 2019 v16.8.5)使用 /W4 /Wx 编译并运行以下内容:

#include <iostream>

template<typename... Ts>
class C
{
public:
    void f(int*);
    void g(Ts*...);
};

template<typename... Ts>
void C<Ts...>::f(int* const pi) {
    using namespace std;
    cout << "f " << *pi << endl;
}

template<typename... Ts>
void C<Ts...>::g(Ts* const... tsargs) {
    using namespace std;
    cout << "g ";
    (cout << ... << *tsargs);
    cout << endl;
}

int main() {
    C<int, float, char> cifc;

    int* pi = new int{ 5 };
    cifc.f(pi);

    float* pf = new float{ 1.0f };
    char* pc = new char{ 'a' };
    cifc.g(pi, pf, pc);
}

但无论是 C++17 还是 C++2a,GCC HEAD 11.0.1 20210 和 Clang HEAD 13.0.0 都没有。

Wandbox