c++ - 使用别名模板时无法将 `std::unique_ptr` 分配给 clang 中的基类

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

以下代码在 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 认为它们不是。关于实际答案是什么,这仍然是一个悬而未决的问题。

关于c++ - 使用别名模板时无法将 `std::unique_ptr` 分配给 clang 中的基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39843027/

相关文章:

c++ - 在 Cygwin 中配置 clang++ 以使用 g++/gcc STL header 的最简单方法?

c++ - 我们如何在 C++ 中组合返回多个值的函数

c++ - 可变参数模板结构,递归类型声明,可能吗?

objective-c - 启用 "Instrument Program Flow"时 objc_msgSend 中的 EXC_BAD_ACCESS

c++ - 将 shared_ptr(this) 插入 vector 会导致 "free(): invalid pointer"错误

C++ 检查队列是否已满?

c++ - 如何从数字输入文件中找到最大数字

c - 初始化一个int有什么副作用吗?

c++ - 为什么 constexpr 不是所有函数的默认值?

c++ - 你能在 C++ 的 string::iterator 中使用 advance() 吗?