Я столкнулся с несоответствием С++ между gcc
(версии 4.8.1
, 4.8.2
) и clang
(версии 3.3
, 3.4
). Интересно, какой из них правильный. Здесь программа:
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);
}
Очевидно, что этот код не предназначен для чего-либо; это агрессивное упрощение того, что появляется в библиотеке Boost Range (с f
упрощением make_iterator_range
). Bad_Type_Fcn
- это функция типа (технически, struct
), которая никогда не должна создаваться, потому что Empty<T>::type
никогда не существует для любого T
. Наличие этого struct
и второй специализированной специализации f()
само по себе не является ошибкой. IRL, f()
предоставляет некоторые функции для определенных типов, для которых Bad_Type_Fcn
не является пустым. Однако это не вызывает беспокойства, поэтому я упростил их. Я все еще хочу, чтобы f()
работал для типов, где Bad_Type_Fcn
пуст.
Я компилирую с {g++|clang++} [-std=c++0x] -pedantic -Wall -Wextra -c
. Выбор стандарта языка, похоже, не имеет значения. С помощью clang
программа компилируется без ошибок или предупреждений. С 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;
Что происходит, так это то, что clang
устраняет вторую перегрузку f()
, возможно (?), исходя из того, что вызов выполняется только с 1 аргументом, integer 42
, а для второй перегрузки требуется 2 аргументы. С другой стороны, gcc
не устраняет вторую перегрузку и вместо этого пытается создать экземпляр struct Bad_Type_Fcn<int>
, что приводит к ошибке.
Неисправность исчезает, если я удалю явное инстанцирование в вызове f()
и вместо этого напишу (void)f(42);
.
Какой из компиляторов прав?