使用别名模板时,无法将 `std::unique_ptr` 分配给 clang 中的基数 class

Can't assign a `std::unique_ptr` to a base class in clang when using an alias template

以下代码在 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 比它应该的更宽松,为什么会这样?

这是CWG issue 1244:

The example in 14.4 [temp.type] paragraph 1 reads in significant part,

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

and says that y and z have the same type.

This would only be true if alias template Z were considered to be equivalent to class template Y. However, 14.5.7 [temp.alias] describes equivalence only for specializations of alias templates, not for the alias templates themselves. Either such rules should be specified, which could be tricky, or the example should be deleted.

我们可以将您的示例缩减为:

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

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