【问题标题】:Can't assign a `std::unique_ptr` to a base class in clang when using an alias template使用别名模板时,无法将`std::unique_ptr`分配给clang中的基类
【发布时间】:2017-02-12 01:44:06
【问题描述】:

以下代码在 gcc 4.9.3 和 clang 3.7.1 上编译并运行良好

// std::unique_ptr
#include <memory>

// Template class for template-template arguments
template <typename Real>
struct Bar {};

// Base class 
template <typename T,template <typename> class XX>
struct Base {};

// Derived class that operates only on Bar 
template <typename Real>
struct Derived : public Base <Real,Bar> {};

// Holds the unique_ptr 
template <typename T,template <typename> class XX>
struct Foo {
    std::unique_ptr <Base <T,XX>> foo;
};

// Create an alias template 
template <typename Real>
using Buz = Bar <Real>;

int main() {
    #if 0
    auto f = Foo <double,Buz> (); //Causes error!
    #else
    auto f = Foo <double,Bar> ();
    #endif
    f.foo =  std::make_unique <Derived <double>> (Derived <double>());
}

但是,如果我们将 #if 0 更改为 #if 1,gcc 会编译,但 clang 不会:

g++ -std=c++14 test03.cpp -o test03_gcc
clang++ -std=c++14 test03.cpp -o test03_clang
test03.cpp:32:11: error: no viable overloaded '='
    f.foo =  std::make_unique <Derived <double>> (Derived <double>());
    ~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/include/g++-v4/bits/unique_ptr.h:249:7: note: 
      candidate function not viable: no known conversion from
      'unique_ptr<Derived<double>, default_delete<Derived<double>>>' to
      'unique_ptr<Base<double, Buz>, default_delete<Base<double, Buz>>>' for
      1st argument
      operator=(unique_ptr&& __u) noexcept
      ^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/include/g++-v4/bits/unique_ptr.h:278:7: note: 
      candidate function not viable: no known conversion from 'typename
      _MakeUniq<Derived<double> >::__single_object' (aka
      'unique_ptr<Derived<double> >') to 'nullptr_t' for 1st argument
      operator=(nullptr_t) noexcept
      ^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/include/g++-v4/bits/unique_ptr.h:357:19: note: 
      candidate function not viable: no known conversion from
      'unique_ptr<Derived<double>, default_delete<Derived<double>>>' to
      'const unique_ptr<Base<double, Buz>, default_delete<Base<double,
      Buz>>>' for 1st argument
      unique_ptr& operator=(const unique_ptr&) = delete;
                  ^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/include/g++-v4/bits/unique_ptr.h:264:22: note: 
      candidate template ignored: disabled by 'enable_if' [with _Up =
      Derived<double>, _Ep = std::default_delete<Derived<double> >]
        typename enable_if< __and_<
                            ^
1 error generated.
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1

在这种情况下使用别名模板有什么问题?或者,如果 gcc 比它应该的更宽松,为什么会这样?

【问题讨论】:

    标签: c++ clang c++14 clang++


    【解决方案1】:

    这是CWG issue 1244

    14.4 [temp.type] 第 1 段中的示例读起来很重要,

    template<template<class> class TT> struct X { };
    template<class> struct Y { };
    template<class T> using Z = Y<T>;
    X<Y> y;
    X<Z> z;
    

    并表示yz 具有相同的类型。

    只有当别名模板Z 被认为等同于类模板Y 时,这才是正确的。但是,14.5.7 [temp.alias] 仅描述了别名模板特化的等效性,而不是别名模板本身的等效性。要么应该指定这样的规则,这可能很棘手,要么应该删除示例。

    我们可以将您的示例简化为:

    std::unique_ptr<Base<double, Buz>> f = 
        std::make_unique<Base<double, Bar>>();
    

    当且仅当BuzBar 被认为是等效的时,这是正确的。 gcc 认为它们是,clang 认为它们不是。至于实际答案是什么,这仍然是一个悬而未决的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-14
      • 2019-11-07
      • 1970-01-01
      • 1970-01-01
      • 2023-01-26
      • 1970-01-01
      • 2015-07-11
      • 2017-05-30
      相关资源
      最近更新 更多