Inferencia de tipo de parámetro de plantilla c++
templates type-inference (1)
Tengo una plantilla en C ++
template<typename T, T* P> struct Ptr {};
entonces puedo usarlo como tal:
const int i = 0;
Ptr<int, &i> ptr;
o
Ptr<decltype(i), &i> ptr;
Pero no quiero especificar el tipo
int
o identidad
i
dos veces, quiero usar solo
Ptr<&i> ptr;
y deje que el compilador
int
parte de tipo
int
por sí mismo.
¿Cómo puedo declarar mi plantilla para hacer eso?
He leído esta pregunta pero la respuesta es usar macros, eso no es bueno: ¿ plantilla de plantilla c ++?
¿Puedo hacer esto solo con una plantilla sin macros? Estoy usando Visual C ++ 2013.
ACTUALIZAR
c ++ 17
introdujo "
P0127R2 Declaración de parámetros de plantilla sin tipo con auto
", lo que permite declarar un parámetro o parámetros de plantilla sin tipo con
auto
como marcador de posición para el tipo real:
template <auto P> struct Ptr {};
Es decir,
P
es un parámetro de plantilla sin tipo.
Su tipo se puede inferir con
decltype(P)
.
auto
en una lista de parámetros de plantilla está sujeto a deducciones bien conocidas y reglas de orden parcial.
En su caso, el tipo puede limitarse a aceptar solo punteros:
template <auto* P> struct Ptr {};
Tenga en cuenta que la sintaxis que utiliza
auto
es suficiente incluso para una inspección más detallada, por ejemplo:
template <typename F>
struct FunctionBase;
template <typename R, typename... Args>
struct FunctionBase<R(*)(Args...)> {};
template <auto F>
struct Function : FunctionBase<decltype(F)> {};
También es posible usar el tipo inferido como una restricción para otros parámetros de plantilla:
template <auto I, decltype(I)... Is>
struct List {};
Vieja respuesta
Como está preguntando acerca de una solución basada en plantillas de clase pura sin la ayuda de definiciones de macro, la respuesta es simple: por ahora (diciembre de 2014, c ++ 14 ) no es posible .
Este problema ya ha sido identificado por el Comité Estándar WG21 C ++ como una necesidad y hay varias propuestas para permitir que las plantillas infieran automáticamente el tipo de argumentos de plantilla sin tipo.
El más cercano es N3601 Parámetros de plantilla implícitos :
Parámetros de plantilla implícitos
El propósito de este ejemplo es eliminar la necesidad de la
template<typename T, T t>
redundantetemplate<typename T, T t>
idioma. Este idioma es ampliamente utilizado, con más de 100k hits en Google.El objetivo es poder reemplazar una declaración de
template<typename T, T t> struct C;
comotemplate<typename T, T t> struct C;
con otra declaración para que podamos instaurar la plantilla comoC<&X::f>
lugar de tener que decirC<decltype(&X::f), &X::f>
.La idea básica es poder decir
template<using typename T, T t> struct C {/* ... */};
para indicar queT
debe deducirse. Para describir con más detalle, consideramos algunos ejemplos extendidos de clases de plantilla y funciones.[...]
La idea clave es que pasar el tipo del segundo parámetro de plantilla es información redundante porque se puede inferir usando la deducción de tipo ordinario del segundo parámetro de tipo. Con eso en mente, proponemos que anteponer un parámetro de plantilla con el uso indica que no debe pasarse explícitamente como un argumento de plantilla, sino que se deducirá de los argumentos de plantilla posteriores que no sean de tipo. Esto inmediatamente nos permite mejorar la usabilidad de
describe_field
siguiente manera.
template<using typename T, T t> struct describe_field { /* ... */ }; /* ... */ cout << describe_field<&A::f>::name; // OK. T is void(A::*)(int) cout << describe_field<&A::g>::arity; // OK. T is double(A::*)(size_t)
Una propuesta similar es la que se incluye en los Tidbits de plantilla N3405 :
T para dos
El ejemplo motivador es un rasgo de tipo de reflexión putativo que da propiedades de un miembro de la clase.
struct A { void f(int i); double g(size_t s); }; /* ... */ cout << describe<&A::f>::name; // Prints "f" cout << describe<&A::g>::arity; // prints 1
La pregunta es "¿cómo debería ser la declaración de descripción?" Dado que toma un parámetro de plantilla que no es de tipo, debemos especificar el tipo del parámetro utilizando el idioma familiar (100k hits en Google)
“template<class T, T t>”
template<typename T, T t> struct describe;
[...]
Nuestra idea clave es que pasar el tipo del segundo parámetro de plantilla es (casi siempre) información redundante porque se puede inferir usando la deducción de tipo ordinario del segundo parámetro de tipo. Con eso en mente, proponemos permitir que
describe
se declare de la siguiente manera.
template<typename T t> struct describe; /* ... */ cout << describe<&A::f>::name; // OK. T is void(A::*)(int) cout << describe<&A::g>::arity; // OK. T is double(A::*)(size_t)
El estado actual de ambas propuestas se puede rastrear en el número 9 del EWG .
Hay otras
discussions
proponen una sintaxis alternativa con
auto
:
template <auto T> struct describe;