Template class type alias failing substitution in member declaration

假如想象 提交于 2020-12-06 04:41:42

问题


Assume you have a templated class like this:

template <typename type>
class Object {
  using length_t = unsigned int;
  
  template <length_t length>
  void put(type (&)[length]);
};

and you declared a put(...) method in it like so. How do you go about declaring that put(...) method outside the class?

  1. Here's one approach someone might take:

    /* ERROR: Doesn't match any declarations(?) */
    template <typename type>
    template <typename Object<type>::length_t length>
    void Object<type>::put(type (&)[length]) {}
    

    but this leads to a peculiar error

    error: no declaration matches 'void Object<type>::put(type (&)[length])'
    
    note: candidate is: 
      template <class type>
      template <unsigned int length>
      void Object<type>::put(type (&)[length])
    
  2. Here's another way to declare the put(...) method such that it works:

    /* SUCCESS: But `length_t` alias isn't used */
    template <typename type>
    template <unsigned int length>
    void Object<type>::put(type (&)[length]) {}
    

    but the length_t type alias defined in the class isn't used.

How does one get the first definition to work so as to keep the use of the class's features (like type aliases) consistent across its declaration & definitions, or is the second definition the only solution here?


回答1:


How does one get the first definition to work so as to keep the use of the class's features (like type aliases) consistent across its declaration & definitions,

I have to admit that I don't understand the error and I don't know how to fix it by changing the definition only. The error message is rather confusing (you should include it in the question).

... or is the second definition the only solution here?

No, it is not. If you are fine with having length_t not as member then this might point you in the right direction:

template <template<typename> typename T>
struct length { using type = int; };

template <template<typename> typename T>
using length_t = typename length<T>::type;


template <typename> struct Object;
template <> struct length<Object> { using type = unsigned int; };

template <typename type>
class Object {
  //using length_t = unsigned int;
  
  template <length_t<Object> length>
  void put(type (&)[length]);
};

template <typename type>
template <length_t<Object> length>
void Object<type>::put(type (&)[length]) {}

length is a "template trait" (not sure if this term actually exists). Instead of having length_t as member of Object you need to provide a specialization for length<Object> (and that needs a forward declaration of Object). The int base case is only for illustration. And if you like you can still add a member to Object to alias length_t<Object>.

Live Demo




回答2:


I think it's a compiler bug, or further more, a defect in standard.

your code actually has NO problem, and is accepted by MSVC. and if you put the definition inside the class, no compiler will think it's ill-formed.

I have posted a question that is similar to this. and I get the result that, CWG2, the ancient issue that nobody knows when it's posted, is still drafting, which means the match rule of out-of-definition is even unspecified. these weird mismatches are because of the different implementations of compilers.

and then, for how to avoid this problem, firstly you can put the definition inside the class. and if it depends on something defined behind the class definition and can not be defined inside, you can:

  1. make it independent: let using length_t = unsigned int; outside.
  2. make it deducible when declaring: compilers may not know if typename Object<type>::length_t and length_t (inside the class) are the same type, although typename Object<type>::length_t is not needed to be deducible. because at the declaring moment, compiler can not ensure if Object<type> is specified and make length_t mismatched, in my mind. so as what @idclev 463035818 said, template<...> using length_t = unsigned int; will make compiler easier to match this definition.


来源:https://stackoverflow.com/questions/64598755/template-class-type-alias-failing-substitution-in-member-declaration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!