参数列表中可选的“名称”?

时间:2018-02-11 10:42:32

标签: c++ templates

template < parameter-list > declaration

参数列表中的每个参数可以是:

  • 非类型模板参数;
  • 类型模板参数;
  • 模板模板参数。

几分钟前,我找到了

  • template<typename>/*(a type template parameter)*/
  • template<int>/*a non-type template parameter*/
在某些情况下,

是合法的。

所以,语法就像:

  • 一个类型模板参数;
    • typename name(可选)
  • 非类型模板参数;
    • 类型名称(可选)
  • ...

这是一个例子

template <typename T>
class ArrayList
{
    std::vector<T> vec;
public:
    template<class> // Mark!
    class Ref {
        ArrayList<T> *array;
        int position;
    public:
        Ref(ArrayList<T> *a, int pos):array(a), position(pos) {};
        Ref<T> &operator=(T v) {
            if (array->vec.size() <= position)
                array->vec.resize(position+1);
            array->vec[position] = v;
        }
        operator T() const {
            if (array->vec.size() <= position)
                throw std::exception();
            return array->vec[position];
        }
    };
    Ref<T> operator[](int p) {return Ref<T>(this, p); }; 
};

我在函数的参数type fun(type) {}中知道类似的习惯用法,唯一的用法是我们不需要nametype就足够了。

我的问题是:

  1. Ref的实施中,template<class>代替template<class T>template<class U>有什么好处。我想这是因为我们这里不需要额外的T/U(确切地说,它是U,因为额外的T会导致阴影错误)template <typename T> class ArrayList
  2. 这个成语的其他好处是什么?(当然,也许没有其他好处)
  3. 除注入课程外,我们何时会在name中排除多余的parameter-list。我希望看到更多的应用程序。

2 个答案:

答案 0 :(得分:1)

  1. 在您的特定示例中,没有任何好处。它没有充分理由使Ref成为会员模板。

  2. 如果我们将模板视为元函数,那么如果可以调用它,则与函数参数相同。我们可以发信号通知该参数被忽略,并且不会影响所产生的特化。您可以在标签调度代码中看到它。例如:

    template<typename> struct tag{};
    
    template<typename T>
    void do_foo_for(tag<T>) = delete;
    
    void do_foo_for(tag<int>) {
      // Do stuff
    }
    
    void do_foo_for(tag<std::string>) {
      // Do stuff
    }
    
    template<typename T>
    void foo() {
      do_foo_for(tag<T>{});
    }
    

    在上面,我们使用tag模板创建一个廉价类型来执行重载解析。当我们希望模板函数的实现根据类型参数做不同时,通常会这样做。由于重载通常比函数模板特化更强大,因此我们会根据tag模板生成的不同类型进行重载。这种类型对于各种重载很重要,但对于模板本身而言,类型的名称并不重要,因此我们不打算命名它。

    标签发送的用途太宽泛,无法在此描述,因此以上是一个玩具示例。但它演示了如何在&#34;类型&#34;上发送函数。

答案 1 :(得分:1)

  

除了注入类,我们何时会在参数列表中排除冗余名称。我希望看到更多的应用程序。

另一个使用示例是使用class / struct模板专业化。

假设您要编写自定义类型特征,以了解某个类型是否为某个类型的std::vector

您可以按如下方式编写

template <typename>
struct isVect : public std::false_type
 { };

template <typename ... Ts>
struct isVect<std::vector<Ts...>> : public std::true_type
 { };

因此默认值为“不是矢量”,但当类型为std::vector<Ts...>时,变为“是矢量”。

注意您需要接收类型,但只有在您需要了解它的专业化中才会知道。

您可以编写说明模板类型

标识符的通用版本
// ................V  you can add a type identifier, but why?
template <typename T>
struct isVect : public std::false_type
 { };

但是你没有使用它,所以为什么要明确这个名字?