Clang 3.5和3.6之间的重载分辨率的这种变化是正确还是错误?

Ed *_*ert 33 clang conversion-operator language-lawyer overload-resolution c++11

下面的代码在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;
};
Run Code Online (Sandbox Code Playgroud)

错误消息是

/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;
          ^
Run Code Online (Sandbox Code Playgroud)

对我来说,这似乎是一个3.6中的错误,在以前的版本中,重载决议确定复制构造函数是最合适的,而不必评估模板参数 - 我试图理解标准中的重载解析注释但我认为只是困惑我更多;)

(这可以通过使构造函数或转换运算符显式我明白来修复,但这不是我们想要的行为)

那里的任何标准专家都知道答案吗?

小智 -1

模板根据需要实例化,我认为 Clang 3.6 实现了 DR,它需要比 3.5 更早地实例化模板。