简体   繁体   English

Gcc和clang之间的C ++不一致

[英]C++ inconsistency between gcc and clang

I came across a C++ inconsistency between gcc (versions 4.8.1 , 4.8.2 ) and clang (versions 3.3 , 3.4 ). 我碰到一个C ++之间的不一致gcc (版本4.8.14.8.2 )和clang (版本3.33.4 )。 I wonder which one is correct. 我想知道哪一个是正确的。 Here's the program: 这是程序:

template < typename T > struct Result {};
template < typename T > struct Empty {};

template < typename T >
struct Bad_Type_Fcn {
    typedef typename Empty< T >::type type;
};

template < typename T >
Result< T >
f( const T& ) {
    return Result< T >();
}

template< class U >
Result< typename Bad_Type_Fcn< U >::type >
f( const U&, int ) {
    return Result< typename Bad_Type_Fcn< U >::type >();
}

int main() {
    (void)f< int >(42);
}

Clearly, this code is not meant to do anything; 显然,这段代码并不意味着什么; it is an aggressive simplification of something that appears in the Boost Range library (with f simplifying make_iterator_range ). 它是对Boost Range库中出现的某些东西的积极简化(使用f简化了make_iterator_range )。 The Bad_Type_Fcn is a type function (technically, a struct ) which should never be instantiated, because Empty<T>::type never exists, for any T . Bad_Type_Fcn是一个类型函数(技术上是一个struct ),它永远不应该被实例化,因为对于任何TEmpty<T>::type永远不存在。 The presence of this struct and of the second template specialization of f() is not an error in itself. 这个struct的存在以及f()的第二个模板特化本身并不是一个错误。 IRL, f() provides some functionality for certain types for which Bad_Type_Fcn is not empty. IRL, f()Bad_Type_Fcn不为空的某些类型提供了一些功能。 However that is not the concern here, which is why I simplified those out. 然而,这不是我们关注的问题,这就是我将其简化的原因。 I still want f() to work for types where Bad_Type_Fcn is empty. 我仍然希望f()适用于Bad_Type_Fcn为空的类型。

I'm compiling with {g++|clang++} [-std=c++0x] -pedantic -Wall -Wextra -c . 我正在编译{g++|clang++} [-std=c++0x] -pedantic -Wall -Wextra -c The language standard selection doesn't seem to make a difference. 语言标准选择似乎没有什么区别。 With clang , the program compiles without errors or warnings. 使用clang ,程序可以编译而不会出现错误或警告。 With gcc , I get an error: 使用gcc ,我收到一个错误:

weird.cpp: In instantiation of ‘struct Bad_Type_Fcn<int>’:
weird.cpp:17:5:   required by substitution of ‘template<class U> Result<typename Bad_Type_Fcn<T>::type> f(const U&, int) [with U = int]’
weird.cpp:22:26:   required from here
weird.cpp:6:43: error: no type named ‘type’ in ‘struct Empty<int>’
         typedef typename Empty< T >::type type;

What seems to be happening is that clang eliminates the second overload of f() , probably(?) on the basis that the call is made with 1 argument only, integer 42 , while the second overload requires 2 arguments. 似乎正在发生的是clang消除了f()的第二个重载,可能是(?),因为调用仅使用1个参数,整数42 ,而第二个重载需要2个参数。 On the other hand, gcc doesn't eliminate the second overload, and instead tries to instantiate struct Bad_Type_Fcn<int> , which results in an error. 另一方面, gcc不会消除第二个重载,而是尝试实例化struct Bad_Type_Fcn<int> ,这会导致错误。

The inconsistency disappears if I remove the explicit instantiation in the call to f() , and write (void)f(42); 如果我在调用f()和write (void)f(42);删除显式实例化,则不一致性消失(void)f(42); instead. 代替。

Which of the compilers is correct? 哪个编译器是正确的?

I remember a WG21 core discussion about this, and one of the Clang developers defended their position by citing 14.7.1p7 我记得有关WG21的核心讨论,其中一位Clang开发者通过引用14.7.1p7来辩护他们的立场

If the overload resolution process can determine the correct function to call without instantiating a class template definition, it is unspecified whether that instantiation actually takes place. 如果重载解析过程可以在不实例化类模板定义的情况下确定要调用的正确函数,则未指定该实例化是否实际发生。

On the other hand, for an ill-formed program (which is the case here when doing the required instantiation), there is no such notion of "the correct function to call", so I agree to the position of another guy in that discussion who said that he can't see that this allows Clang to go that route. 另一方面,对于一个格式错误的程序(这是执行所需实例化时的情况),没有“正确的调用函数”的概念,所以我同意在讨论中另一个人的立场谁说他看不出这让Clang走那条路。

In the example of p7 it shows code that is well-formed both with and without doing the additional instantiation. 在p7的示例中,它显示了在执行和不执行其他实例化的情况下格式良好的代码。

In any case , even if Clang is allowed to do it, the well-formedness of your program would then rely on particular happenstances (unspecified behavior). 无论如何 ,即使允许Clang这样做,你的程序的良好构成也会依赖于特定的偶然事件(未指明的行为)。 The Standard therefore doesn't anymore require your program to be accepted, and honestly I don't know what that means. 因此,标准不再要求接受您的计划,老实说,我不知道这意味着什么。 I regard such code as being ill-formed. 我认为这些代码是不正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM