【问题标题】:Printing a non type template inner class打印非类型模板内部类
【发布时间】:2015-08-03 02:04:53
【问题描述】:

我有一个指向类模板实例(例如 Counter)的非类型类模板(例如 Counted)。只要两个模板类是兄弟,一切都可以正常工作,例如编写打印运算符。

现在出于几个原因,我想将 Counted 作为内部类移动到 Counter 中,但我发现自己无法编写打印运算符。

Here's a working "sibling class" version,主要代码在这里:

template < class Count >
struct Counter {
    using count_type = Count;
    count_type instances = 0;
};

template < class Cnt, Cnt& c>
struct Counted {
    using id_type = typename Cnt::count_type;
    id_type id;
    Counted() : id(c.instances) { ++c.instances; }
    ~Counted() { --c.instances; }
};

template < class Cnt, Cnt& c >
std::ostream& operator<<(std::ostream& os, Counted<Cnt,c> sib) {
    os << "printing sibling " << sib.id;
    return os;
}

using SCounter = Counter<std::size_t>;
SCounter sc;
using SCounted = Counted<SCounter, sc>;

Here's the not compiling "inner class" version 这里有主要代码:

template < class Count >
struct Counter {
    using count_type = Count;
    count_type instances = 0;

    template <Counter& c>
    struct Counted {
        using id_type = count_type;
        id_type id;
        Counted() : id(c.instances) { ++c.instances; }
        ~Counted() { --c.instances; }
    };
};

template < class Count, Counter<Count>& c >
std::ostream& operator<<(std::ostream& os,
      typename Counter<Count>::template Counted<c>& sib) {
    os << "printing inner " << sib.id;
    return os;
}

using SCounter = Counter<std::size_t>;
SCounter sc;
using SCounted = SCounter::Counted<sc>;

错误:

prog.cpp: In function 'int main()':
prog.cpp:32:15: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
  std::cout << j << std::endl;
               ^
In file included from /usr/include/c++/4.9/iostream:39:0,
                 from prog.cpp:1:
/usr/include/c++/4.9/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Counter<unsigned int>::Counted<(* & sc)>]'
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^

我的代码、我的编译器是否有问题,还是标准不允许这样做?

【问题讨论】:

  • 在您的operator&lt;&lt; 中,typename Counter&lt;Count&gt;:: 中的Count 位于非推断上下文 中。也就是说,编译器无法从函数参数中推断出它。您可以使 operator&lt;&lt; 更通用 - 如 template&lt;class C&gt; std::ostream&amp; operator&lt;&lt;(std::ostream&amp;, C const&amp;) - 然后限制它,例如通过 SFINAE。
  • Counted 类模板中将operator&lt;&lt; 定义为非成员朋友函数更容易。
  • 此外,[temp.deduct.type]p13 “不能从非类型模板参数的类型推导出模板类型参数。”所以template&lt;class C, Counter&lt;C&gt;&amp; r, template&lt;Counter&lt;C&gt;&amp;&gt; class T&gt; ostream&amp; operator&lt;&lt;(ostream&amp;, T&lt;r&gt; const&amp;);也是不允许的,因为C可能不能从r推导出来。
  • 感谢 dyp,与operator&lt;&lt; 成为朋友正是我想要的。我应该考虑到这一点。也感谢您的解释。

标签: c++ c++11 type-inference


【解决方案1】:

Koenig 运算符是您想要的:

  template <Counter& c>
    struct Counted {
      using id_type = count_type;
      id_type id;
      Counted() : id(c.instances) { ++c.instances; }
      ~Counted() { --c.instances; }

      friend std::ostream& operator<<(
        std::ostream& os,
        Counted const& sib
      ) {
        os << "printing inner " << sib.id;
        return os;
      }           
    };
};

我们在这里创建一个friend operator&lt;&lt;。当您尝试将 &lt;&lt;Counted 实例一起使用时,将通过 ADL(或 Koenig 查找)找到它。

Counted的每种类型创建不同的函数,并且不做模板推导。

【讨论】:

  • “Koenig 运营商就是你想要的” 不过,这是一个侵入性的更改/解决方案。另外,你需要更多 friend ;)
猜你喜欢
  • 2011-10-08
  • 2016-10-23
  • 2018-12-05
  • 2017-01-04
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
相关资源
最近更新 更多