SFINAE具有无效的函数类型或数组类型参数?

Joh*_*itb 22 c++ arrays templates sfinae

请考虑以下代码:

template<typename T>
char (&f(T[1]))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }
Run Code Online (Sandbox Code Playgroud)

我期待它做SFINAE并选择第二次超载,因为替换TT[1]收益率

 void [1]()
Run Code Online (Sandbox Code Playgroud)

当然,这是一种无效的类型.在将模板参数替换为函数参数并检查有效的结果类型(如14.8.2 [temp.deduct]描述)之后,完成参数类型(数组 - >指针)的调整.

但是考勤和海湾合作委员会都未能编制上述内容.两者都有不同的诊断.

Comeau说:

"ComeauTest.c",第2行:错误:不允许使用函数数组 char (&f(T[1]))[1];

GCC说(版本4.3.3):

错误:ISO C++禁止零大小的数组 c

意思是,海湾合作委员会不会无法替代,但它选择了第一次超载f,返回sizeof1,而不是像Comeau那样无法替代它.

什么编译器是正确的,我的代码是否有效?请参阅或引用答案中适当的标准部分.谢谢!


更新:标准本身在列表中包含这样的示例14.8.2/2.我不知道为什么我先忽略它:

template <class T> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array
Run Code Online (Sandbox Code Playgroud)

虽然这个例子只是提供信息,但它显示了所有这些神秘段落的意图,并且似乎表明上面的代码应该起作用并拒绝第一次重载.

Ric*_*den 12

一个小小的音符,虽然非常罕见,我发现在某些情况下我认为Comeau编译器有错误 - 虽然,这些场合非常罕见,它总是值得双倍和三倍检查你的假设!

我可能有一个g ++行为的原因.我不确定它的参数类型何时被调整:

考虑以下:

template<typename T>
struct A
{
  void bar (T[10]);
};

template<typename T>
void A<T>::bar (T*)
{
}
Run Code Online (Sandbox Code Playgroud)

'bar'的定义是合法的,因为"T [10]"衰减为"T*".我没有在标准中看到任何禁止编译器对模板声明执行8.3.5调整的内容,并且它还提高了过载匹配的性能.

将此应用于您的示例,g ++可能会将其视为:

template<typename T>
char (&f( T* ))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }
Run Code Online (Sandbox Code Playgroud)

在上面,替换参数是函数的合法指针,而不是函数数组.

所以,对我来说问题是 - 是否有某些事情禁止对函数参数(8.3.5)进行两次调整?

就个人而言,我认为允许调整发生两次是有意义的,否则它会使函数模板重载的匹配变得复杂

总之,我认为g ++根据它如何处理衰减的数组参数来选择第一个重载是有效的,而Comeau错误的是没有函数数组的演绎失败.

当然这现在意味着(如果Comeau被修复)那么每个编译器会选择不同的重载并且仍然符合标准!:(

编辑:

为了说明我的观点,请考虑以下代码:

template <typename T> void foo ( T * );
template <typename T> void foo ( T * const );
template <typename T> void foo ( T [] );
template <typename T> void foo ( T [10] );
template <typename T> void foo ( T [100] );

void bar () 
{
  foo < void() > ( 0 );
}
Run Code Online (Sandbox Code Playgroud)

在这里,foo已经多次声明和重新声明.编译器应该使用哪个声明以及哪个参数类型应用14.8.2中列出的规则?

我的观点是标准没有说明上述内容.我还要说,对此的任何措辞都必须将其作为"未定义"或"实现定义"行为.