【问题标题】:Why would an Alias Template be treated differently than the aliased type template when it comes to friendship?在友谊方面,为什么别名模板与别名类型模板的处理方式不同?
【发布时间】:2015-11-02 15:05:58
【问题描述】:

我们在代码库中观察到一个令人惊讶的行为,即未能应用友谊关系。 (目前仅使用 Clang 3.6 版编译)

我们可以将其简化为这个最小的示例。假设我们有以下模板类定义:

template <int>
class Element
{};


// Forward declaration of FriendBis
template <template <int> class> class FriendBis;

class Details
{
    friend class FriendBis<Element>;
    int mValue = 41;
};

template <template <int> class>
class FriendBis
{
public:
    void useDetails(const Details &aDetails)
    {
        aDetails.mValue;
    }
};

这里,Details 声明 FriendBis 的实例化,其单个模板模板参数替换为 Element 是它的 friend。因此,以下客户端代码编译成功:

FriendBis<Element> fb1;
fb1.useDetails(Details());

 问题

现在,让我们介绍额外的trait 模板类型,其全部目的是将proto 定义为Element 模板的模板别名:

struct trait
{
    template <int N>
    using proto = Element<N>;
};

下面的客户端代码无法编译:

FriendBis<trait::proto> fb2;
fb2.useDetails(Details());

这让我们感到惊讶,因为trait::protoElement 的别名,但一个可以编译而另一个不能编译。

  • 这是预期的行为吗?
    • 如果是这样,这个限制的理由是什么?
    • 有解决方法吗? (同时保持有限的友谊,而不是将FriendBis 的所有实例化为朋友)。

【问题讨论】:

标签: c++ templates c++11 friend


【解决方案1】:

别名模板与其别名的类型不是同义词:trait::protoElement 是不同的类型。当模板 ID 引用 trait::proto then 的特化时,它等价于替换类型。简单来说,trait::proto 不是Element,而是trait::proto&lt;0&gt; Element&lt;0&gt;

回答您的问题:

  • 是的,这是预期行为

  • 理由是别名类型可能比Element&lt;N&gt; 复杂得多,它可能类似于Element&lt;ElementForInt&lt;N+1&gt;::value&gt;。那么映射就不明显了。

  • 我想不出一个解决方法。如果您想检查模板模板参数是否与其他模板相同为别名模板帐户,您可以检查这两个名称的实例化是否相同类型,例如std::is_same&lt;T&lt;0&gt;, Element&lt;0&gt;&gt;,但我不确定你如何在朋友声明中实现这一点。

【讨论】:

  • 这是CWG 1286。另外,trait::protoElement 不是类型。
  • 感谢您的回答!我无法理解您给出的理由示例。您能否详细说明为什么它不明显? @TC 谢谢你的链接。
猜你喜欢
  • 2014-09-30
  • 1970-01-01
  • 2016-06-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-18
  • 2021-12-06
  • 2021-12-18
相关资源
最近更新 更多