Search code examples
c++type-conversiontypedeflanguage-lawyerconversion-operator

Is it possible to declare the conversion function returning array reference without the typedef?


Here's a conversion function returning an array reference:

struct S { 
    typedef int int_array_20[20];
    operator int_array_20& ();
};

Is it possible to do the same thing without typedef? What I've tried:

struct S { 
    operator int (&()) [10];
};

but clang complains:

error: C++ requires a type specifier for all declarations
    operator int (&()) [10];
                  ~ ^
error: conversion function cannot have any parameters
    operator int (&()) [10];
    ^
error: must use a typedef to declare a conversion to 'int [10]'
error: conversion function cannot convert to an array type

Does:

must use a typedef to declare a conversion to 'int [10]'

mean typedef is indispensable?

EDIT
If typedef is necessary, it's impossible to create a conversion function template like the following, because couldn't define a typedef template, is it right?

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

Solution

  • Yes, this is indeed required we can see this by going to the cppreference section user-defined conversion which says:

    Function and array operators [] or () are not allowed in the declarator (thus conversion to types such as pointer to array requires a typedef: see below). Regardless of typedef, conversion-type-id cannot represent an array or a function type.

    We can find this in the draft C++ standard section 12.3.2 Conversion functions which says:

    The conversion-type-id shall not represent a function type nor an array type. The conversion-type-id in a conversion-function-id is the longest possible sequence of conversion-declarators. [ Note: This prevents ambiguities between the declarator operator * and its expression counterparts. [ Example:

    &ac.operator int*i; // syntax error:
                        // parsed as: &(ac.operator int *)i
                        // not as: &(ac.operator int)*i
    

    The * is the pointer declarator and not the multiplication operator. —end example ] —end note ]

    and the grammar for conversion-type-id is as follows:

    conversion-type-id:
      type-specifier-seq conversion-declaratoropt
    conversion-declarator:
      ptr-operator conversion-declaratoropt
    

    which is more restricted then a declarator whose grammar looks like this:

    declarator:
      ptr-declarator
      noptr-declarator parameters-and-qualifiers trailing-return-type
    ptr-declarator:
      noptr-declarator
      ptr-operator ptr-declarator
    noptr-declarator:
      declarator-id attribute-specifier-seqopt
      noptr-declarator parameters-and-qualifiers
      noptr-declarator [ constant-expressionopt] attribute-specifier-seqopt
      ( ptr-declarator )
    

    One alternative as chris mentioned was to use an identity class:

    template <typename T>
    struct identity
    {
        typedef T type;
    };
    

    you would use it as follows:

    operator typename identity<int(&)[10]>::type() ;