Код ниже компилируется в Visual Studio 2013, gcc 4.8, clang 3.4 и clang 3.5 (Apple LLVM 6.0), но не компилируется в clang 3.6 (через Apple LLVM 6.1)
Код - это упрощенная версия сложного класса в нашей кодовой базе, которая является минимальной, необходимой для выявления проблемы.
Суть проблемы в том, что построение копии TYPED_VALUE
в 3.6, вычисляет шаблонный оператор преобразования для типа STRING
из-за наличия конструктора, который принимает a STRING
; это приводит к оценке std::is_constructible
, которая приводит к необходимости определения STRING
(которую мы не можем здесь предоставить, приведет к циклической зависимости в полном коде).
class STRING;
class TYPED_VALUE
{
public:
TYPED_VALUE( const TYPED_VALUE& ) = default; // explicit or implicit doesn't make a difference
TYPED_VALUE( const STRING & ) {}
template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
operator TYPE( void ) const = delete;
};
class TYPED_STORAGE
{
public:
TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}
TYPED_VALUE value;
};
Сообщение об ошибке
/type_traits:2329:38: error: incomplete type 'SICORE::STRING' used in type trait expression
: public integral_constant<bool, __is_constructible(_Tp, _Args...)>
^
/main.cpp:348:99: note: in instantiation of template class 'std::__1::is_constructible<SICORE::STRING, const SICORE::STRING &>' requested here
template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
^
/main.cpp:349:9: note: while substituting prior template arguments into non-type template parameter [with TYPE = SICORE::STRING]
operator TYPE( void ) const = delete;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
/main.cpp:355:56: note: while substituting deduced template arguments into function template 'operator type-parameter-0-0' [with TYPE = SICORE::STRING, $1 = (no value)]
TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}
^
/main.cpp:340:11: note: forward declaration of 'SICORE::STRING'
class STRING;
^
Для меня это похоже на ошибку в версии 3.6, в предыдущих версиях разрешение перегрузки определяет, что конструктор копирования лучше всего подходит без необходимости оценивать аргументы шаблона - я попытался понять примечания о разрешении перегрузки в стандарте, но я думаю это меня просто смутило;)
(Это можно устранить, если я реализую конструктор или оператор преобразования явным, но это не то поведение, которое мы хотим)
Любые стандартные эксперты там знают ответ?