【问题标题】:How to make template type inference work in this case?在这种情况下如何使模板类型推断起作用?
【发布时间】:2010-07-08 09:40:29
【问题描述】:

再一次,我希望 C++ 有更强的typedefs:

#include <vector>

template<typename T>
struct A {
    typedef std::vector<T> List;
};

template<typename T>
void processList(typename A<T>::List list) {
    // ...
}

int main() {
    A<int>::List list;
    processList<int>(list); // This works.
    processList(list);      // This doesn't.
}

显然,编译器将list 视为std::vector&lt;int&gt; 而不是A&lt;int&gt;::List,因此无法将其与预期的A&lt;T&gt;::List 匹配。

在实际情况下,它是一个较长的类型名称,经常重复,而且很麻烦。除了让processList 接受vector 之外,还有什么方法可以让模板类型推断对我有用吗?

【问题讨论】:

    标签: c++ templates type-inference


    【解决方案1】:

    有什么方法可以让模板类型推断对我有用吗?

    不,这就是所谓的不可演绎的上下文

    但是,你为什么还需要这个?传递序列的惯用方式是通过迭代器:

    template<typename It>
    void processList(It begin, It end) {
        typedef typename std::iterator_traits<It>::value_type T;
        // ....
    }
    
    int main() {
        A<int>::List list;
        processList(list.begin(), list.end()); // works now
        return 0;
    }
    

    (请注意,在您的问题中,您传递了 vector 按值,这是一件坏事。对于迭代器来说,这很好,甚至可以首选。)

    但是,如果你真的很绝望,你可以让函数推断出任何带有一定数量模板参数的容器:

    template<typename T, typename A, template<typename,typename> C>
    void processList(C<T,A>& cont) {
        // ....
    }
    

    但是请注意,这将匹配任何具有两个模板参数的模板。 OTOH,它不会匹配像 std::map 这样的容器,它有不同数量的参数。

    【讨论】:

    • 嗯,好点子。我想我不太关心“惯用语”,因为这仅供一个班级内部使用。传递一个(我在这个简化示例中省略的...的引用)事物本身使得调用站点的代码更短。
    • 为简单起见,我按值传递了向量。在实践中,我当然传递了一个 const 引用。您的更新很整洁;不是说我会使用它(我没那么绝望),但记住这一点很好。
    • +1 但要注意(对于编辑)标准容器没有固定数量的参数——它是实现定义的,实现只需要为模板的任何额外参数提供默认值以便假设标准编译中存在的签名的实例化。
    【解决方案2】:

    知道了。使用继承来创建一个实际上不同的类型:

    template<typename T>
    class A : public std::vector<T> {
    };
    

    在这种情况下我不需要非默认构造函数。

    【讨论】:

    • 因为太可怕了:std::vector 没有虚拟析构函数。
    • 好吧,他可能不会通过基类指针多态地使用它,所以这可能不是问题。 Thomas,也许您可​​以发布最终代码,以便我们看看它是否会带来其他问题。
    • 我最终选择了 sbi 的解决方案,传递了迭代器。像魅力一样工作。
    【解决方案3】:

    您的情况有一个简单的解决方案:

    template <class C>
    void processList(C const& list)
    {
      typedef typename C::value_type value_type;
      BOOST_STATIC_ASSERT_MSG((boost::same_type< C, typename A<value_type>::List >),
        NOT_A_A_LIST_TYPE,
        (C, A<value_type>)
      );
      // do your stuff
    }
    

    注意,C++0x 即将到来!

    template <typename second>
    using TypedefName = SomeType<OtherType, second, 5>;
    

    我想知道这是否可行

    template <typename value>
    using AList = typename A<value>::List;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 1970-01-01
      • 2018-12-12
      相关资源
      最近更新 更多