Home Optional "name" in parameter-list?
Reply: 2

Optional "name" in parameter-list?

czxyl
1#
czxyl Published in 2018-02-11 10:42:31Z

template < parameter-list > declaration

Each parameter in parameter-list may be:

  • a non-type template parameter;
  • a type template parameter;
  • a template template parameter.

Minutes ago, I found

  • template<typename>/*(a type template parameter)*/
  • template<int>/*a non-type template parameter*/

are legal in some cases.

So, syntax is like:

  • a type template parameter;
    • typename name(optional)
  • a non-type template parameter;
    • type name(optional)
  • ...

Here is an example

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); }; 
};

I know similar idiom in function's parameter type fun(type) {}, the only usage of it is we don't need the name, type is enough here.

My question is:

  1. In the implementation of Ref, What is the benefit of template<class> instead of template<class T> or template<class U>. I guess that it is because we don't need extra T/U here(Precisely, it is U, because extra T will cause shadowing error) template <typename T> class ArrayList
  2. What're the other benefits of the idiom?(Of course, perhaps no other benefits)
  3. Except for injected class, when will we exclude the redundant name in parameter-list. I hope to see more applications.
StoryTeller
2#
StoryTeller Reply to 2018-02-11 11:01:05Z
  1. In your particular example there is no benefit whatsoever. It makes Ref a member template for no good reason.

  2. The benefit, if you can call it that, is the same as with function parameters, if we treat templates as meta-functions. We can signal that the parameter is ignored, and doesn't affect the resulting specialization. You can see it in tag dispatch code. For instance:

    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>{});
    }
    

    In the above, we use that tag template to create a cheap type with which to perform overload resolution. This is often done when we want the implementation of a template function do differ based on the type parameter. Since overloading is generally more robust than function template specialization, we overload based on the different types generated from the tag template. The type is important to the various overloads, but for the template itself the name of the type is not at all important, so we don't bother naming it.

    The uses of tag dispatch are too broad to describe here, so the above is a bit of a toy example. But it demonstrates how a function may be dispatched on a "type".

max66
3#
max66 Reply to 2018-02-11 12:42:01Z

Except for injected class, when will we exclude the redundant name in parameter-list. I hope to see more applications.

Another example of use is with class/struct template specialization.

Suppose you want to write a custom type traits to know if a type is a std::vector of something.

You can write it as follows

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

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

So the default is "isn't a vector" but when the type is in form std::vector<Ts...>, become "is a vector".

Observe that you need receive the type but only in the specialization you need know something about it.

You can write the general version explicating an identifier of the template type

// ................V  you can add a type identifier, but why?
template <typename T>
struct isVect : public std::false_type
 { };

but you don't you use it, so why explicit the name?

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.301968 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO