tipos retorno programacion predefinidas parametros funciones funcion ejemplos con c++ templates member-pointers

c++ - retorno - parametros programacion ejemplos



¿Por qué es importante el orden de declaración para pasar un puntero a función miembro como un argumento de plantilla? (3)

Generalmente, el orden de declaración en la definición de clase no tiene efectos.

Eso es toda una exageración. Algunos de los usos de las declaraciones que aparecen más adelante en la definición de clase están permitidos, a mi entender:

  • argumentos predeterminados (como usted mencionó; pero no argumentos predeterminados de la plantilla)
  • usos dentro de un cuerpo de función, función-try-block o inicializador de miembro
  • Inicializadores en clase (C ++ 11 o posterior)

Además, como se ha mencionado, el orden de los miembros de los datos afecta el orden de construcción y destrucción. Además, reordenar cosas entre unidades de traducción puede causar sorprendentemente una violación de ODR.

Mira este código:

template <typename T, void (T::*pfn)()> struct Testee {}; class Tester { private: void foo() {} public: using type_t = Testee<Tester, &Tester::foo>; };

Se compila con éxito con g++ -std=c++14 -Wall -Wextra .

Sin embargo, cuando cambio el orden de foo y type_t , se produce un error:

$ cat test.cpp template <typename T, void (T::*pfn)()> struct Testee {}; class Tester { public: using type_t = Testee<Tester, &Tester::foo>; private: void foo() {} }; int main() { } $ g++ -std=c++14 -Wall -Wextra -pedantic test.cpp test.cpp:6:36: error: incomplete type ‘Tester’ used in nested name specifier using type_t = Testee<Tester, &Tester::foo>; ^ test.cpp:6:47: error: template argument 2 is invalid using type_t = Testee<Tester, &Tester::foo>; ^

Generalmente, el orden de las declaraciones en las definiciones de clase no tiene efecto en la resolución de nombres. Por ejemplo:

struct A // OK { void foo(int a = val) { } static constexpr const int val = 42; }; struct B // OK { static constexpr const int val = 42; void foo(int a = val) { } };

Sin embargo, tiene un efecto en este caso. ¿Por qué?


Esto no está realmente relacionado con las plantillas. Obtienes un error similar en:

class Tester { public: using type_t = decltype(&Tester::foo); private: void foo() {} };

Es cierto que una clase es (Estándar 9.2 / 2):

considerado como completo dentro de los cuerpos de función, los argumentos predeterminados, las declaraciones de uso que introducen constructores heredados (12.9), las especificaciones de excepción y los inicializadores de refuerzo o igual para los miembros de datos no estáticos (incluyendo cosas en clases anidadas).

Sin embargo, la definición de un tipo de miembro no está en esa lista, por lo que solo puede usar nombres declarados antes de ese punto.


La deducción de la plantilla se produce antes de que el compilador pase a toda la clase, lo que significa que el compilador en ese momento aún no sabe nada para instanciar a Testee .

Esto se relaciona con la razón por la que las plantillas pueden funcionar con clases declaradas hacia adelante como parámetros de plantilla, pero no con las clases que se declaran más adelante en el código.

Lea más sobre esto aquí: Deducción de plantilla de clase

Para crear una instancia de una plantilla de clase, se deben conocer todos los argumentos de la plantilla, pero no se deben especificar todos los argumentos de la plantilla.

ACTUALIZAR

Investigué un poco por qué compila su ejemplo con la función y el parámetro predeterminado. Resulta que es válido C ++ y una excepción para la declaración de parámetros predeterminados. Es probable que el compilador analice estos parámetros predeterminados después de que conozca a toda la clase para que esto funcione.

Los miembros de clase no estáticos no están permitidos en los argumentos predeterminados (incluso si no se evalúan), excepto cuando se usan para formar un puntero a miembro o en una expresión de acceso de miembro.

http://en.cppreference.com/w/cpp/language/default_arguments