Pregunta

Mientras lee otra pregunta, llegué a un problema con la ordenación parcial, que reduje a la siguiente prueba de los casos

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

int main() {
  // GCC chokes on f(0, 0) (not being able to match against T1)
  void *p = 0;
  f(0, p);
}

Para ambas plantillas de función, el tipo de función de la especialización que entra resolución de sobrecarga es void(int, void*). Pero ordenación parcial (según Comeau y GCC) ahora dice que la segunda plantilla es más especializado. Pero ¿por qué?

Déjame ir a través de la ordenación parcial y mostrar dónde tengo preguntas. Puede Q ser un tipo maquillada único que se utiliza para la determinación de ordenación parcial de acuerdo con 14.5.5.2.

  • Transformado parámetro-lista para T1 (Q inserta): (Q, typename Const<Q>::type*). Los tipos de los argumentos son AT = (Q, void*)
  • Transformado parámetro-lista para T2 (Q inserta): BT = (Q, void*), que son también los tipos de los argumentos.
  • parámetro-list-no transformadas para T1: (T, typename Const<T>::type*)
  • parámetro-list-no transformadas para T2: (T, void*)

Como C ++ 03-bajo especifica esto, que no usamos la intención de que he leído en varios informes de defectos. La lista de parámetros anteriormente transformado para T1 (llamado AT por mí) se utiliza como lista de argumentos para 14.8.2.1 "Deducir argumentos de plantilla a partir de una llamada a la función" .

14.8.2.1 no necesita para transformar AT o BT sí más (como, la eliminación de declaradores de referencia, etc.), y va directamente a 14.8.2.4, que de forma independiente para cada par A / P no escriba deducción:

  • AT contra T2: { (Q, T) , (void*, void*) } . T es el único parámetro de plantilla aquí, y se dará cuenta de que T debe Q. Tipo de deducción tiene éxito trivialmente para AT contra T2.

  • BT contra T1: { (Q, T) , (void*, typename Const<T>::type*) } . Se dará cuenta de que se T Q, también aquí. typename Const<T>::type* es un contexto no-deducido, por lo que no será utilizada para deducir nada.


Esta es mi primera pregunta: ¿Esto ahora utilizar el valor de T deducida para el primer parámetro? Si la respuesta es no, entonces la primera plantilla es más especializado. Esto no puede ser el caso, debido a que ambos CCG y Comeau dicen que la segunda plantilla es más especializado, y que no creo que están equivocados. Por lo que suponemos "sí", e insertamos en void* T. El párrafo (14.8.2.4) dice "La deducción se realiza de forma independiente para cada par y los resultados se combinan entonces" y "En ciertos contextos, sin embargo, el valor no participa en el tipo de deducción, pero en su lugar utiliza los valores de argumentos de plantilla que, o bien se dedujeron en otro lugar o explícitamente. " Esto suena como 'sí' también.

por lo tanto Deducción tiene éxito también, para cada par A / P. Ahora, cada plantilla es al menos tan especializado como el otro, ya que la deducción no también se basan en las conversiones implícitas y tuvo éxito en ambas direcciones. Como resultado, la llamada debe ser ambiguo.

Así que mi segunda pregunta: ¿Ahora, ¿por qué las implementaciones dicen que la segunda plantilla es más especializado? Lo momento me paso por alto?


Editar : He probado especialización explícita y ejemplificación, y ambos, en versiones recientes de GCC (4.4) me dicen que la referencia a laespecialización es ambigua, mientras que una versión antigua de GCC (4.1) no se eleva ese error ambigüedad. Esto sugiere que las últimas versiones del CCG tienen orden parcial de plantillas de funciones incompatibles.

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

template<> void f(int, void*) { }
  // main.cpp:11: error: ambiguous template specialization 
  // 'f<>' for 'void f(int, void*)'
¿Fue útil?

Solución

Aquí está mi ir en esto. Estoy de acuerdo con Charles Bailey que la incorrecta paso es pasar de Const<Q>::Type* a void*

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

Las medidas que quiere tomar son:

14.5.5.2/2

  

Dados dos plantillas de función sobrecargados, si uno es más especializado que otra puede ser determinada mediante la transformación de cada plantilla a su vez y el uso de deducción argumento (14.8.2) para compararlo con el otro.

14.5.5.2/3-b1

  

Para cada parámetro de plantilla tipo, sintetizar un tipo único y sustituto que para cada ocurrencia de ese parámetro en la lista de parámetros de función, o para una función de conversión de plantilla, en el tipo de retorno.

En mi opinión, los tipos se sintetizan de la siguiente manera:

(Q, Const<Q>::Type*)    // Q1
(Q, void*)              // Q2

No veo cualquier fraseología que requiere que el segundo parámetro sintetizado de T1 ser void*. No conozco ningún precedente para que, en otros contextos, ya sea. El tipo Const<Q>::Type* es de tipo perfectamente válido dentro del sistema de tipo C ++.

Así que ahora realizamos los pasos deductivos:

Q2 a T1

Tratamos de deducir los parámetros de plantilla para T1 por lo que tenemos:

  • Parámetro 1: T se deduce que se Q
  • Parámetro 2: contexto Nondeduced

A pesar de que el parámetro 2 es un contexto no deducido, la deducción todavía ha tenido éxito porque tenemos un valor para T.

Q1 a T2

Deducir los parámetros de plantilla para T2 tenemos:

  • Parámetro 1: T se deduce que se Q
  • Parámetro 2: void* no coincide con lo que el fracaso Const<Q>::Type* deducción
  • .

En mi humilde opinión, aquí es donde la norma nos defrauda. El parámetro no depende de lo que no está muy claro lo que debe suceder, sin embargo, mi experiencia (basado en una lectura de bizqueados 14.8.2.1/3) es que, incluso cuando el tipo de parámetro P no es dependiente, entonces el tipo de argumento debe coincidir con una a él.

Los argumentos sintetizados de T1 se pueden utilizar para especializarse T2, pero no viceversa. por lo tanto, T2 es más especializado que T1 y también lo es la mejor función.


ACTUALIZACIÓN 1:

Sólo para cubrir el poing sobre Const<Q>::type estar vacío. Consideremos el siguiente ejemplo:

template<typename T>
struct Const;

template<typename T>
void f(T, typename Const<T>::type*) // T1
{ typedef typename T::TYPE1 TYPE; }

template<typename T>
void f(T, void*)                    // T2
{ typedef typename T::TYPE2 TYPE ; }

template<>
struct Const <int>
{
  typedef void type;
};

template<>
struct Const <long>
{
  typedef long type;
};

void bar ()
{
  void * p = 0;
  f (0, p);
}

En lo anterior, Const<int>::type se utiliza cuando estamos realizando las reglas habituales de resolución de sobrecarga, pero no cuando nos llegar a las reglas sobrecarga parciales. No sería correcto para elegir una especialización arbitrario para Const<Q>::type. Puede que no sea intuitivo, pero el compilador es muy feliz de tener un tipo synthasized de la forma Const<Q>::type* y utilizarlo durante tipo de deducción.


ACTUALIZACIÓN 2

template <typename T, int I>
class Const
{
public:
  typedef typename Const<T, I-1>::type type;
};

template <typename T>
class Const <T, 0>
{
public:
  typedef void type;
};

template<typename T, int I>
void f(T (&)[I], typename Const<T, I>::type*)     // T1
{ typedef typename T::TYPE1 TYPE; }

template<typename T, int I>
void f(T (&)[I], void*)                           // T2
{ typedef typename T::TYPE2 TYPE ; }


void bar ()
{
  int array[10];
  void * p = 0;
  f (array, p);
}

Cuando la plantilla Const se instancia con algún valor I, recursivamente crea la instancia de sí mismo hasta I llega a 0. Esto es cuando se selecciona la Const<T,0> especialización parcial. Si tenemos un compilador que sintetiza algún tipo real de los parámetros de la función, entonces, ¿qué valor será el compilador elegir para el índice de la matriz? Por ejemplo, 10? Bueno, esto estaría bien para el ejemplo anterior, pero no se correspondería con la Const<T, 10 + 1> especialización parcial que, al menos conceptualmente, se traduciría en un número infinito de instancias recursivas de la primaria. Cualquiera sea el valor que se selecciona podríamos modificar la condición de fin de ser que el valor de + 1, y entonces tendríamos un bucle infinito en el algoritmo de ordenación parcial.

No veo cómo el algoritmo de ordenación parcial podría crear una instancia correctamente Const encontrar what type realmente es.

Otros consejos

Editar: Después de estudiar Sonido metálico (por Doug Gregor) de su algoritmo de ordenación parcial, que han llegado a de acuerdo con el resto de los carteles que el ejemplo original no está más 'adecuados' para ser ambigua - a pesar de que la norma no es tan clara como podría ser acerca de lo que debe suceder en este tipo de situaciones. He editado este post para indicar mis pensamientos revisadas (para mi propio beneficio y de referencia). En particular el algoritmo de Clang aclaró que 'typename Const<T>::type' no se traduce en 'vacío' durante la etapa de ordenación parcial -. Y que cada A / P par se deduce independientes entre sí

Al principio me preguntaba por qué se considera ambigua la siguiente:

        template<class T> void f(T,T*);  // 1

        template<class T> void f(T, int*); // 2

        f(0, (int*)0); // ambiguous

(The above is ambiguous because one cannot deduce f1(U1,U1*) from f2(T,int*), and going the other way, one cannot deduce f2(U2,int*) from f1(T,T*). Neither is more specialized.)

pero el siguiente no sería ambigua:

        template<class T> struct X { typedef int type; };
        template<class T> void f(T, typename X<T>::type*); // 3
        template<class T> void f(T, int*); // 2

(La razón por la que uno podría esperar que sea ambigua es si el siguiente llegara a suceder:
 - f3(U1,X<U1>::type*) -> f3(U1, int*) ==> f2(T,int*) (deduction ok, T=U1)
 - f2(U2,int*) ==> f3(T, X<T>::type*) (deduction ok, T=U2 makes X<U2>::type* -> int*)
Si esto fuera cierto, ninguno de los dos sería más especializado que el otro.)

Después de estudiar algoritmo de ordenación parcial de Sonido metálico es evidente que tratan a '3' por encima como si fuera:

template<class T, class S> void f(T, S*); // 4

así que la deducción de algunas únicas en 'U' en contra 'nombre de tipo X :: tipo' tendrá éxito -

  • f3(U1,X<U1>::type*) is treated as f3(U1, U2*) ==> f2(T,int*) (deduction not ok)
  • f2(U2,int*) ==> f3(T,S* [[X<T>::type*]]) (deduction ok, T=U2, S=int)

Y así '2' es claramente más especializado que '3'.

  

parámetro-list transformadas T1 (Q   insertado): (Q, TypeName   Const :: tipo *). Los tipos de la   argumentos son AT = (Q, void *)

Me pregunto si eso es realmente una simplificación correcta. Al sintetizar el tipo Q, ¿Se le permite evocar una especialización para Const a los efectos de determinar el orden de specliazation plantilla?

template <>
struct Const<Q> { typedef int type; }

Esto implicaría que T2 no es al menos tan especializado como T1 porque un parámetro void* no coincide segundo parámetro de T1 para cualquier parámetro de plantilla dada.

Edit: Por favor, ignore este post - Después de estudiar algoritmo de sonidos metálicos para la ordenación parcial tal como se aplica por Doug Gregor (a pesar de que se lleva a cabo sólo parcialmente partir de este escrito - parece que la lógica que es relevante a la pregunta del OP se lleva a cabo de forma suficientemente adecuada ) - parece como si se trata del contexto undeduced como otro parámetro de plantilla. Lo que sugiere que la sobrecarga con el vacío * argumento explícito debe ser la versión más especializado y no debe haber ninguna ambigüedad. Como de costumbre Comeau es correcta. Ahora en cuanto a la redacción de la norma que defina claramente este comportamiento - eso es otra cosa ...

Desde este puesto también fue publicada el comp.lang.c ++ moderado, y parece estar causando cierta confusión allí también -. I pensé que había puesto mi respuesta a ese grupo también aquí - ya que la discusión es obviamente relevante para el pregunta hecha aquí.

  

On Jul 25, 1:11 pm, Bart van Ingen Schenau <b...@ingen.ddns.info> wrote:

     

You are going one step too fast here. How do you know (and would the compiler know) that there is no specialisation of Const<Q> such that Const<Q>::type != void?

     

As far as I can see, the compiler would transform the parameter-list of A to: AT=(Q, <unknown>*). To call B with these parameters requires an implicit conversion (<unknown>* to void*) and therefore A is less specialised than B.

Creo que esto es incorrecto. Al comprobar para ver cuál es la función más especializada (durante parcial de pedidos), el compilador transforma el parámetro de la lista de (Q, void*) - es decir, que en realidad crea una instancia del correspondiente plantilla (mejor adaptación) y mira en su interior por el valor de 'tipo' - en este caso, a partir en la plantilla principal, será void *.

Con respecto a su punto relativo a la especialización parcial - en la comprobación de qué plantilla está más especializado que el otro, el único tipo que puede ser utilizado es el tipo generado única - si hay otras especializaciones en el punto de creación de instancias de la declaración (cuando se está haciendo la resolución de sobrecarga) éstas serán consideradas. Si se agrega más adelante, y que debe ser seleccionado estará violando el ODR (de acuerdo con 14.7.4.1)

Las especializaciones parciales / explícitos también obtendrán durante considertaion formación de conjunto de candidatos - pero esta vez utilizando los tipos de los argumentos reales a la función. Si la especialización parcial mejor coincidencia (de X) resulta en una Tipo de función que tiene una secuencia de conversión mejor implícito para algunos parámetro, que nunca llegan a la fase-ordenación parcial, y que conseguirá seleccionado "mejor" la función (antes de llegar a la parcial fase de pedido)

A continuación se muestra un ejemplo con comentarios sobre lo que debe estar pasando en varios pasos:

    template<class T, bool=true> struct X;  // Primary

    template<class T> struct X<T,true> { typedef T type; };  // A
    template<> struct X<int*,true> { typedef void* type; };  // B


    template<class T> void f(T,typename X<T>::type); //1
    template<class T> void f(T*,void*); //2


    int main()
    {
      void* pv;
      int* pi;


      f(pi,pi);   
      // two candidate functions: f1<int*>(int*,void*),  f2<int>(int*,void*)
      // Note: specialization 'B' used to arrive at void* in f1
      // neither has a better ICS than the other, so lets partially order
      // transformed f1 is f1<U1>(U1,X<U1,true>::type) --> f1<U1>(U1,U1) 
      //       (template 'A' used to get the second U1)
      // obviously deduction will fail (U1,U1) -> (T*,void*)
      // and also fails the other way (U2*, void*) -> (T,X<T>::type)
      // can not partially order them - so ambiguity 




      f(pv,pv);  
      // two candidate functions: f1<void*>(void*,void*), f2<void>(void*,void*)
      // Note: specialization 'A' used to arrive at second void* in f1
      // neither has a better ICS than the other, so lets partially order
      // transformed f1 is f1<U1>(U1,X<U1>::type) --> f1<U1>(U1,U1) 
      //       (template 'A' used to get the second U1)
      // obviously deduction will fail (U1,U1) -> (T*,void*)
      // and also fails the other way (U2*, void*) -> (T,X<T>::type)
      // can not partially order them - so ambiguity again             

    }

También vale la pena mencionar que si la plantilla primaria no tiene una definición - a continuación, SFINAE opera durante la fase de ordenación parcial, ni se puede deducir de la otra, y la ambigüedad debería resultar.

Además, si se agrega otra plantilla que llevaría a otro partido si el punto de instantation de cualquiera de esas funciones se mueve en otra parte de la unidad de traducción que se violaría claramente el ODR.

  

On Jul 25, 1:11 pm, Bart van Ingen Schenau <b...@ingen.ddns.info> wrote:

     

En primer lugar, por ser más especializado significa que se trata de un menor número de tipos donde   esa plantilla se puede seleccionar mediante la resolución de sobrecarga.   El uso de este, las reglas para la ordenación parcial se pueden resumir como: Intentar   encontrar un tipo de A tal que A puede ser llamado, pero no B, o una sobrecarga   Resolución prefiere llamar A. Si se puede encontrar ese tipo, entonces B es más   especializada que a.

No hay discusión aquí. Pero en base a las reglas ya que son actualmente, el ejemplo de la OP tiene que ser ambigua.


Finalmente, estos son explícitas, respuestas claras a las dos preguntas específicas planteadas por litb:

1) ¿Será esto ahora utilizar el valor de T deducida para el primer parámetro?
Sí - por supuesto, tiene que hacerlo, que está haciendo la deducción argumento de plantilla - los 'enlaces' tienen que ser mantenidos.

2) Ahora, ¿por qué las implementaciones dicen que la segunda está más especializado en su lugar?
Debido a que están equivocados;)

Espero que esto pone el tema para descansar - Por favor, déjame know si hay algo que todavía no está claro:)

Editar: litb planteó un buen punto en su comentario - tal vez indicando que la plantilla principal siempre obtendrá utilizado para la creación de instancias con el tipo único generada es demasiado fuerte un comunicado.
Hay casos en que no se recurra a la plantilla principal.
Lo que quiero decir es que cuando se está produciendo la ordenación parcial, algún tipo único es generado se utiliza para que coincida con la mejor especialización. Tienes razón, no tiene que ser la plantilla principal. He editado el idioma arriba para hacerlo. También planteó una cuestión relativa a la definición de una plantilla coincidente mejor después del punto de instantation. Esa será una violación de la ODR acuerdo con el apartado de punto de instanciación.


  

El estándar dice que una vez que se crean los pares A / P (utilizando las reglas de transformación como se describe en temp.func.order) que se deducen una contra la otra mediante deducción argumento de plantilla (temp.deduct) - y que los mangos de sección el caso de contextos no deducido, instanciar la plantilla y su tipo anidado, provocando puntos de instanciaciones. La sección temp.point maneja las violaciónes ODR (el significado de la ordenación parcial no debe cambiar independientemente de los puntos de instantation dentro de una unidad de traducción). Todavía no estoy seguro de que la confusión proviene de? - Hace 1 hora Faisal Vali [eliminar este comentario]

     

litb: "Tenga en cuenta que el paso que pone en Q Const :: tipo para construir los argumentos no está cubierta explícitamente por la regla SFINAE.   Las reglas SFINAE trabajan con deducción de argumento, puso a los párrafos que ponen Q en la lista de parámetros de función plantilla de función están en 14.5.5.2. "

Las reglas SFINAE tienen que ser utilizados aquí - ¿cómo podrían no estarlo? Siento que es lo suficientemente implicada - no voy a negar que podría ser más claro, y mientras yo animo al Comité que aclarara esto -. i no creo que necesita ser aclarado para interpretar su ejemplo suficientemente

Permítanme ofrecer una manera de vincularlos. A partir de (14.8.2): "Cuando se especifica una lista de argumentos de plantilla explícita, los argumentos de plantilla deben ser compatibles con el lista de parámetros de plantilla y debe dar lugar a un tipo de función válido como se describe a continuación; deducción de lo contrario Tipo falla "

A partir de (14.5.5.2/3) "La transformación utilizada es: - Para cada parámetro de plantilla tipo, sintetizar un tipo único y sustituto que para cada ocurrencia de ese parámetro en la lista de parámetros de función, o para una función de conversión de plantilla, en el tipo de retorno ".

En mi mente, la cita anterior implica que una vez que "crear" tipos generados únicas para cada parámetro de plantilla, la declaración de la función tiene que ser implícitamente instancia por explícitamente el suministro de los tipos únicos como argumentos de plantilla a nuestra plantilla de función. Si esto se traduce en un inválido Tipo de función, entonces no sólo la transformación, pero lo más importante la posterior plantilla argumento deducción necesario parcialmente ordenar la función falla.

A partir de (14.5.5.2/4) "Uso de la lista de parámetros función transformada, lleve a cabo la deducción argumento en contra de la otra plantilla de función. La plantilla transformado es al menos tan especializado como el otro si, y sólo si , la deducción tiene éxito y los tipos de parámetros deducidos son una coincidencia exacta (por lo que la deducción no se basa en las conversiones implícitas). "

Si la lista de parámetros función transformada conduce a la sustitución fracaso, entonces sabemos deducción no podría haber tenido éxito. Y puesto que la deducción no tuvo éxito, no es tan especializado como el otro - eso es todo lo que necesitamos saber para proceder en ordenación parcial los dos.

  

litb: Yo también estoy seguro qué sucede en este caso: template<typename T> struct A;   template<typename T> void f(T, typename A<T>::type); template<typename T> void f(T*, typename A<T>::type); sin duda,   eso está indentado ser un código válido, pero haciendo un tipo ::, se producirá un error porque en el   contexto definición de plantilla, A no está definido todavía"   También tenga en cuenta que no hay PDI definido para ejemplificaciones plantilla resultantes de esta   tipo de sustitución al tratar de determinar un orden (orden parcial no depende   en cualquier contexto. Es una propiedad estática de dos plantillas de funciones implicadas).   Creo que esto se parece a un problema en el estándar que debe ser fijo.

Ok - Me parece ver donde estamos viendo las cosas de manera diferente. Si entiendo correctamente usted, usted está diciendo que como estas plantillas de funciones se declararon, el compilador es mantener un seguimiento de la ordenación parcial entre ellos, independientemente de la resolución de sobrecarga que no penetren disparado para seleccionar entre ellos. Si así es como usted lo interpreta, entonces yo puedo ver por qué se puede esperar el comportamiento anterior que usted describe. Pero no creo que la norma siempre requiere o exige que.

Ahora, la norma es claro que el orden parcial es agnóstico con el tipo que se utiliza en llamar a la función (creo esto es lo que se está refiriendo a cuando usted lo describe como una propiedad estática y que sea independiente del contexto).

El estándar también está claro que sólo se preocupa de pedido acerca parcial (invoca ordenación parcial) entre plantillas de funciones durante el proceso de resolución de sobrecarga (13.3.3 / 1) si y sólo si no podía escoger el mejor funcionamiento basado en ICS o de si se trata de una plantilla y el otro no lo es. [Ordenación parcial de especializaciones parciales plantilla de clase es un tema aparte y en mi mente utiliza el contexto relevante (otras definiciones de plantilla) que requiere la creación de instancias de esa clase en particular.]

Por lo tanto, en mi opinión, ya que la maquinaria del orden parcial de plantillas de función se invoca cuando la sobrecarga se lleva a cabo la resolución, que tiene que utilizar una parte relevante del contexto (definiciones de plantilla y especializaciones) disponibles en el momento en que se realiza la resolución de sobrecarga.

Así que basado en mi interepretation, de acuerdo con su ejemplo el uso de 'plantilla de estructura A' anteriormente, el código es válido. La ordenación parcial no se hace en el contexto de definición. Pero si / cuando suceda para invocar la resolución de sobrecarga entre las dos funciones de escritura de una llamada a f ((int *) 0,0) - y en ese momento cuando el compilador ya sea intenta montar una declaración candidato o parcialmente a la orden (si se llega al paso a la ordenación parcial) Si una expresión o de tipo no válido resultados como parte del tipo de función, SFINAE nos ayuda y le dice nosotros que la deducción plantilla de falla (en lo que se refiere parcial de pedidos, que implica que uno no puede ser más especializado que el otro, si ni siquiera se podía transformar la plantilla).

Ahora lo que respecta a los puntos de interés - si usted está convencido, como yo, que los tipos de funciones transformadas se supone que deben representar instanciaciones implícitas utilizando listas de argumentos plantilla suministrada explícitamente (utilizando los tipos generados de forma única) a continuación, las siguientes citas estándar son relevantes:

14.6.4.1/1 Para una especialización de plantilla de función, una plantilla de especialización función miembro, o una especialización para una función miembro o miembro de datos estáticos de una plantilla de clase, si la especialización está implícitamente instancia porque se hace referencia desde dentro de otra especialización de plantilla y el contexto de la que se hace referencia depende de un parámetro de plantilla, el punto de instanciación de la especialización es el punto de instanciación de la especialización que encierra.

A mi modo de interpretar esto es que el POI del tipo de función transformado y el tipo de función es el origianl mismo que el punto de interés para aquellas funciones creadas por la llamada a la función.

  

litb: Desde orden parcial es más bien sólo se   a property of the syntactic form of parameters (i.e "T*" against "T(*)[N]"),   Yo votaría por la que se modifica la especificación (como "si Q aparece en un nombre de especificador anidada   una cualificada Identificación del nombramiento de un tipo, entonces el tipo de llamada es "Q")   O diciendo que el tipo de llamada es otro t únicoipo.   This means that in template<typename T> void f(T, typename Const<T>::type*);   the argument list is (Q, R*), for example.   Same for template<typename T> void f(T*, typename ConstI<sizeof(T)>::type);   the arg lisst would be (Q*, R). A similar rule would be needed for non-type parameters, of course.   Tendría que pensar en ello y hacer algunos casos de prueba para ver si esto produciría ordenamientos naturales, sin embargo.

Aah - ahora usted está sugiriendo una posible solución que resuelve la ambigüedad en favor de lo que todos intuitivamente esperar - esto es un problema aparte, y si bien me gusta la dirección se está desplazando en, como tú, yo también tendría que poner un poco de pensamiento en él antes de proclamar su capacidad de trabajo.

Gracias por continuar la discusión. Ojalá así que no solo se limitan a la colocación de los comentarios.

Ya que se puede editar mis mensajes, no dude en responder dentro del post si eso es más fácil.

scroll top