SFINAE 具有无效的函数类型或数组类型参数? [英] SFINAE with invalid function-type or array-type parameters?

查看:33
本文介绍了SFINAE 具有无效的函数类型或数组类型参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑此代码:

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

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

int main() { char c[sizeof(f<void()>(0)) == 2]; }

我预计它会执行 SFINAE 并选择第二个重载,因为将 T 替换为 T[1] 会产生

I expected it doing SFINAE and chosing the second overload, since substitution of T into T[1] yields

 void [1]()

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

Which is an invalid type, of course. Adjustment of parameter types (array->pointer) is done after substituting template parameters into function parameters and checking for valid resulting types like 14.8.2 [temp.deduct] describes.

但是 comeau 和 GCC 都无法编译上述内容.两者都有不同的诊断.

But both comeau and GCC fail to compile the above. Both with different diagnostics.

Comeau 说:

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

"ComeauTest.c", line 2: error: array of functions is not allowed char (&f(T[1]))[1];

GCC 说(版本 4.3.3):

GCC says (version 4.3.3):

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

error: ISO C++ forbids zero-size array c

意思是,GCC没有替换失败,但是它选择了f的第一个重载,返回一个sizeof为1,而不是像前面那样没有替换它科莫.

Meaning, GCC does not fail to substitute, but it chooses the first overload of f, returning a sizeof of 1, instead of failing to substitute it up front like Comeau.

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

What compiler is right and is my code valid at all? Please refer to or quote the proper Standard section in your answer. Thanks!

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

Update: The Standard itself contains such an example in the list at 14.8.2/2. I don't know, why I overlooked it first:

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

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

While the example is only informative, it shows the intention of all those mysterious paragraphs and seems to show the code above should work and reject the first overload.

推荐答案

一个小笔记,虽然很少见,但我发现有些场合我相信 Comeau 编译器错了——虽然,这些场合是如此罕见,以至于它总是值得两倍和三倍检查您的假设!

A small note, although very rare, I have found some occasions where I believe that the Comeau compiler has it wrong - although, these occasions are so rare that its always worth double and triple checking your assumptions!

我可能对 g++ 的行为有理由.我不确定它的调整参数类型时准确指定:

I may have a reason for the behaviour of g++. I'm not sure its specified exactly when parameter types are adjusted:

考虑以下事项:

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

template<typename T>
void A<T>::bar (T*)
{
}

'bar' 的定义是合法的,因为 "T[10]" 衰减为 "T*".我愿意在标准中看不到任何禁止编译器对模板声明执行 8.3.5 的调整,并且在重载匹配方面也提高了性能.

The definition of 'bar' is legal, as "T[10]" decays to "T*". I do not see anything in the standard that prohibits the compiler from performing the adjustments of 8.3.5 against the template declaration, and it also improves performance when it comes to overload matching.

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

Applying this to your example, g++ might be treating it as:

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

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

int main() { char c[sizeof(f<void()>(0)) == 2]; }

在上面,被替换的参数是一个合法的指向函数,而不是函数数组.

In the above, the substituted parameter is a legal pointer to function, rather than an array of functions.

所以,对我来说,问题是 - 是否有什么东西禁止函数参数(8.3.5)两次调整?

So, the question for me is - is if there is something that prohibts the adjustments for the function parameters (8.3.5) twice?

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

Personally, I think it makes sense to allow the adjustments to happen twice since otherwise it complicates the matching of function template overloads

总而言之,我认为 g++ 选择第一个重载是有效的基于它如何处理衰减的数组参数,Comeau 是错误的不会出现函数数组的推导失败.

In conclusion, I think its valid for g++ to select the first overload based on how it treates decaying array parameters, and Comeau is wrong not to have a deduction failure for the array of functions.

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

Of course this now means that (if Comeau was fixed) then each compiler would choose a different overload and would still be standards compliant! :(

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

Just to illustrate my point, consider the following code:

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

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

Here, foo has been declared and redeclared several times. Which declaration, and so which parameter type, should the compiler apply the rules listed in 14.8.2?

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

My point is that the standard doesn't say anything about the above. I would also go as far as to say that any wording on this would have to leave it as either "undefined" or "implementation defined" behaviour.

这篇关于SFINAE 具有无效的函数类型或数组类型参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆