为什么对指针的参数包进行常量限定是错误的?
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 都没有。
当实现接受指向 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 都没有。