【问题标题】:Correct practice using 'using' in C++ templates在 C++ 模板中使用“使用”的正确做法
【发布时间】:2013-09-03 14:40:46
【问题描述】:

我有一个在内部使用多个 STL 列表的小类

template<class T>
class MC_base {

  using OBJ_LIST  = std::list<T>;
  using OBJ_VAL   = typename OBJ_LIST::value_type;
  using OBJ_ITR   = typename OBJ_LIST::iterator;
  using OBJ_CITR  = typename OBJ_LIST::const_iterator;

  OBJ_LIST A,B,C;
  ...
};

使用using 语句,如果我在类定义中编写一个迭代器,它看起来又好又干净:

OBJ_ITR begin() { return A.begin(); };
OBJ_ITR end()   { return A.end();   };
OBJ_CITR begin() const { return A.begin(); };
OBJ_CITR end()   const { return A.end();   };

再次在类定义中编写新函数很容易,因为我可以在需要时简单地使用名称 OBJ_XXXX 名称。此外,如果我稍后决定更改容器类型(比如std::vector),我只需更改一行,只要我的新容器支持所有相同的操作,一切都应该是无缝的。

但是当我想在类定义之外定义一个新的类函数时,这是有问题的

template<class T>
OBJ_ITR MC_base<T>::foo(OBJ_ITR x) { ... }

我不确定如何“引出” using 语句,以便它们与模板一起正常工作,而不是为过于冗长的每个函数定义它们。另外,我不想用我的 using 语句污染命名空间。

有没有合适的方法使用using 和模板?

【问题讨论】:

    标签: c++ templates c++11 using


    【解决方案1】:

    您可以使用尾随返回类型。类型在类的范围内查找,与参数类型一样,因此嵌套类型不需要限定。

    template<class T>
    auto MC_base<T>::foo(OBJ_ITR x) -> OBJ_ITR { ... }
    

    【讨论】:

    • +1 太好了。我还考虑了本回答中的解决方案,但这通常要紧凑得多。 _gx 的评论里都有,不过……
    • (因为我在那里评论)现场示例here
    • @gx_:对不起,我没有注意到你已经在评论中回答了;在添加我的之前,我刚刚阅读了另一个答案。
    • 问题:如果声明中没有使用尾随返回类型,是否可以在定义中使用它?
    • @BenVoigt:我没想到。当我尝试它时它起作用了,不允许它似乎很愚蠢,但这并不一定意味着它是允许的。
    【解决方案2】:

    在类之外,您需要限定名称。您还需要使用 typename 关键字来向编译器保证这些名称是 every 专业化中的类型。

    template<class T>
    typename MC_base<T>::OBJ_ITR MC_base<T>::foo( typename MC_base<T>::OBJ_ITR x ) { ... }
    

    9.3p2 要求

    出现在类定义之外的成员函数定义应该出现 在包含类定义的命名空间范围内。

    这可以防止对这些名称所在的定义使用更嵌套的范围。更不用说那些名字依赖于模板参数的问题了。


    最好的解决方案可能是内联编写这些函数。这些是模板类的成员,因此无论如何都必须将它们包含在头文件中。

    【讨论】:

    • 现在有一个语法可以在作用域是类的时候延迟函数返回类型,看起来像template &lt;T&gt; auto Myclass::Func( arg) -&gt; NestedClassTypeFromMyClass { //...
    • @Hooked @BenVoigt 参数类型不需要整个类型名限定的东西,因为我们已经在类的范围内。并且使用尾随返回类型会更短:template&lt;class T&gt; auto MC_base&lt;T&gt;::foo(OBJ_ITR x) -&gt; OBJ_ITR { ... }ideone.com/j7embB
    • @gx_ 这是使用auto 的好方法。为了后代,你能把它放在自己的答案中吗?
    • @Hooked 我实际上预计 Ben Voigt 会在他的答案中添加这个替代方案,但似乎 Mike Seymour 在我看到你的回复之前就把它作为他自己的答案发布了。
    • @gx_ 在我的世界里,我们称之为被挖走。无论哪种方式,您通过 Mike S. 的回答似乎更多的是 C++11,所以我将把接受更改为他的。然而,这个答案中的信息对于理解 Ben 的问题非常有价值!
    猜你喜欢
    • 2015-01-16
    • 1970-01-01
    • 2022-08-22
    • 1970-01-01
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多