This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-19


395. Conversion operator template syntax

Section: 11.4.8.3  [class.conv.fct]     Status: NAD     Submitter: Daveed Vandevoorde     Date: 18 Dec 2002

A posting in comp.lang.c++.moderated prompted me to try the following code:

  struct S {
    template<typename T, int N> (&operator T())[N];
  };

The goal is to have a (deducible) conversion operator template to a reference-to-array type.

This is accepted by several front ends (g++, EDG), but I now believe that 11.4.8.3 [class.conv.fct] paragraph 1 actually prohibits this. The issue here is that we do in fact specify (part of) a return type.

OTOH, I think it is legitimate to expect that this is expressible in the language (preferably not using the syntax above ;-). Maybe we should extend the syntax to allow the following alternative?

  struct S {
    template<typename T, int N> operator (T(&)[N])();
  };

Eric Niebler: If the syntax is extended to support this, similar constructs should also be considered. For instance, I can't for the life of me figure out how to write a conversion member function template to return a member function pointer. It could be useful if you were defining a null_t type. This is probably due to my own ignorance, but getting the syntax right is tricky.

Eg.

  struct null_t {
    // null object pointer. works.
    template<typename T> operator T*() const { return 0; }
    // null member pointer. works.
    template<typename T,typename U> operator T U::*() const { return 0; }
    // null member fn ptr.  doesn't work (with Comeau online).  my error?
    template<typename T,typename U> operator T (U::*)()() const { return 0; }
  };

Martin Sebor: Intriguing question. I have no idea how to do it in a single declaration but splitting it up into two steps seems to work:

  struct null_t {
    template <class T, class U>
    struct ptr_mem_fun_t {
      typedef T (U::*type)();
    };

    template <class T, class U>
    operator typename ptr_mem_fun_t<T, U>::type () const {
      return 0;
    }
  };

Note: In the April 2003 meeting, the core working group noticed that the above doesn't actually work.

Note (June, 2010):

It has been suggested that template aliases effectively address this issue. In particular, an identity alias like

    template<typename T> using id = T;

provides the necessary syntactic sugar to be able to specify types with trailing declarator elements as a conversion-type-id. For example, the two cases discussed above could be written as:

    struct S {
        template<typename T, int N>
          operator id<T[N]>&();
        template<typename T, typename U>
          operator id<T (U::*)()>() const;
    };

This issue should thus be closed as now NAD.

Rationale (August, 2011):

As given in the preceding note.