tipos programacion plantillas funciones ats c++ templates c++11 std-function

programacion - Usando argumentos de plantilla ''nulos'' en C++



programacion ats c++ (5)

Tomemos el siguiente ejemplo mínimo:

using Type1 = std::function<void(void)>; template <typename T> using Type2 = std::function<void(T)>; Type1 whyDoesThisWork; Type2<void> andYetThisDoesNot;

Si aparece el segundo alias de tipo, aparece el error "El argumento puede no tener el tipo ''void''". (Lo probé con Xcode 4.5, Clang / c ++ 11 / libc ++, OS X 10.7).

Encuentro esto curioso: hubiera esperado que Type1 y Type2<void> comportaran de manera idéntica. ¿Que está pasando aqui? ¿Y hay una manera de volver a escribir el segundo alias de tipo para que pueda escribir Type2<void> y obtener std::function<void(void)> lugar de un error?

Editar Probablemente debería agregar que la razón por la que quiero esto es para permitir algo como lo siguiente:

template <typename ... T> using Continuation = std::function<void(T...)>; auto someFunc = []() -> void { printf("I''m returning void!/n"); }; Continuation<decltype(someFunc())> c;

Continuation<decltype(someFunc())> convierte en Continuation<void> y Continuation<decltype(someFunc())> el error.


Cuando se declara que una función toma un parámetro de tipo void , como en std::function<void(void)> , eso es realmente una manera ridícula de decir que toma cero parámetros. Pero la forma en que ha declarado Type2 es como una std::function con una firma que no devuelve nada (nulo), pero que requiere 1 parámetro. void no es un tipo que se pueda usar como parámetro, es solo una forma de declarar que no hay parámetros. Por lo tanto, no funciona con Type2, porque requiere un tipo real que pueda usarse como parámetro.


El vacío se puede interpretar como un parámetro vacío si se lo pasa a una función. Después de todo, no estás usando un puntero de vacío.

void func (void)

se convierte en

void func ()


La respuesta corta es "las plantillas no son sustitución de cadenas". void f(void) solo tiene significado en la medida en que es un alias para void f() en C ++, para ser compatible con C al revés.

El primer paso es usar variadics, como se señala en otra parte.

El segundo paso es averiguar cómo asignar las funciones de retorno de void a ... bueno, tal vez algo como std::function<void()> , o tal vez algo más. Digo tal vez algo más porque a diferencia de los otros casos, no puede llamar a std::function<void()> foo; foo( []()->void {} ); std::function<void()> foo; foo( []()->void {} ); - No es una verdadera continuación.

Algo como esto tal vez:

template<typename T> struct Continuation { typedef std::function<void(T)> type; }; template<> struct Continuation<void> { typedef std::function<void()> type; };

entonces úsalo así:

auto someFunc = []()->void {}; Continuation<decltype(someFunc())>::type c;

Lo que te da el tipo que deseas. Incluso se podría agregar en una aplicación a continuación:

template<typename T> struct Continuation { typedef std::function<void(T)> type; template<typename func, typename... Args> static void Apply( type const& cont, func&& f, Args... args) { cont( f(args...) ); } }; template<> struct Continuation<void> { typedef std::function<void()> type; template<typename func, typename... Args> static void Apply( type const& cont, func&& f, Args... args) { f(args...); cont(); } };

lo que le permite aplicar una continuación a una ejecución de una función de manera uniforme si el tipo entrante es un vacío o si es un tipo no vacío.

Sin embargo, me gustaría preguntar "¿por qué quieres hacer esto"?


No tengo una respuesta real, solo lo que dije en el comentario: No puede tener void como un tipo de función, como en:

int foo(int, char, void, bool, void, void); // nonsense!

Creo que T(void) solo está permitido como una notación de compatibilidad para C (que distingue declaraciones y prototipos , de manera muy diferente a C ++, y que necesita poder decir "sin argumentos").

Entonces, la solución debería ser variad:

template <typename ...Args> using myType = std::function<void(Args...)>;

De esa manera usted no puede tener argumentos adecuadamente:

myType<> f = []() { std::cout << "Boo/n"; }


Varias respuestas ya explican el razonamiento. Para agregar a esas respuestas, la especificación dice (C ++ 11 §8.3.5 [dcl.func] / 4):

Una lista de parámetros que consiste en un solo parámetro sin nombre de tipo no dependiente void es equivalente a una lista de parámetros vacía. Excepto en este caso especial, un parámetro no tendrá el tipo cv void .

En su ejemplo de Type2 , la T en void(T) es un tipo dependiente - depende de un parámetro de plantilla.