34

下面的代码在 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由于存在接受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 中的一个错误,在以前的版本中,重载决议确定复制构造函数是最合适的,而无需评估模板参数 - 我试图理解标准中的重载决议注释,但我认为这只是混淆我更多;)

(这可以通过明确构造构造函数或转换运算符来解决,但这不是我们想要的行为)

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

4

3 回答 3

1

我相信 Clang 产生这个错误是正确的:

第 10 段中 C++ 标准的 [temp.inst] 部分说:

如果以涉及重载解析的方式使用函数模板或成员函数模板特化,则将隐式实例化特化的声明 (14.8.3)。

形成对调用 TYPE_VALUE 的构造函数的重载候选进行排名所需的隐式转换序列需要转换运算符的实例化。并且对 trait 使用不完整的类型参数不会形成无效类型,因此这不是替换失败,而是硬错误。

于 2016-08-02T07:01:57.027 回答
0

的复制构造函数TYPED_VALUE使用对 的引用STRING,不应对其进行评估。
我认为这是一个铿锵的错误。
我已经很长时间没有阅读新的 c++ 标准了,但是,我无法确定它没有改变。

于 2016-07-21T01:24:13.657 回答
-1

模板是根据需要实例化的,我认为 Clang 3.6 实现了一个 DR,它需要在 3.5 之前实例化一个模板。

于 2015-08-13T17:31:30.890 回答