2009-08-13 14 views
17

Si tengo un prototipo que tiene este aspecto:¿Cómo pasar una matriz constante literal a una función que toma un puntero sin usar una variable C/C++?

function(float,float,float,float) 

me puede pasar valores de la siguiente manera:

function(1,2,3,4); 

Así que si mi prototipo es la siguiente:

function(float*); 

¿Hay alguna forma en que puedo lograr algo como esto?

function({1,2,3,4}); 

Sólo en busca de una forma perezosa para hacer esto sin crear una variable temporal, pero me parece que no puede clavar la sintaxis.

+0

Gracias por el consejo. Supongo que esperaba respuestas rápidas y sucias para una pregunta rápida y sucia, pero tu respuesta exploró algunos estilos alternativos en los que no había pensado. ¡Muy apreciado! – sinoth

Respuesta

27

Usted puede hacerlo en C99 (pero no ANSI C (C90) o cualquier curr variante ent de C++) con literales compuestos. Ver la sección 6.5.2.5 del estándar C99 para los detalles sangrientos. Aquí hay un ejemplo:

// f is a static array of at least 4 floats 
void foo(float f[static 4]) 
{ 
    ... 
} 

int main(void) 
{ 
    foo((float[4]){1.0f, 2.0f, 3.0f, 4.0f}); // OK 
    foo((float[5]){1.0f, 2.0f, 3.0f, 4.0f, 5.0f}); // also OK, fifth element is ignored 
    foo((float[3]){1.0f, 2.0f, 3.0f}); // error, although the GCC doesn't complain 
    return 0; 
} 

GCC también lo proporciona como una extensión de C90. Si compila con -std=gnu90 (valor predeterminado), -std=c99 o -std=gnu99, compilará; si compila con -std=c90, no lo hará.

+0

Uno podría obviamente también compilar con '-std = gnu89' (pero no' -std = c89'), ya que es sinónimo de '-std = gnu90' (y '-std = c90') (estoy seguro de que conoces a este Adam, es más para los demás en caso de que no lo hicieran: P). – RastaJedi

2

La mala noticia es que no hay sintaxis para eso. La buena noticia es que esto cambiará con la próxima versión oficial del estándar C++ (prevista para el próximo año o dos). La nueva sintaxis se verá exactamente como usted describe.

+1

heh heh, el próximo año o dos:] Es bueno saber que esto será en C++ 0x. – sinoth

+0

Dudo en dos años. Beta 10 de Visual Studio ya tiene algunas características de C++ 0x integradas, y g ++ 4.4 ya tiene listas de inicializadores (http://gcc.gnu.org/projects/cxx0x.html). Se retrasó hasta 2010, probablemente en el primer trimestre. – GManNickG

0

No, no puedes hacer eso. No tengo el estándar disponible aquí, así que no puedo dar una referencia exacta, pero lo más parecido a lo que pide se ofrecen constantes de cadena, es decir

function(char *); 
function("mystring"); 

es tratado por el compilador como

char * some_pointer = "mystring"; 
function(char *); 
function(some_pointer); 

No hay forma de que otros tipos de variables se traten de esta manera.

4

Se puede crear un compuesto literal:

function ((float[2]){2.0, 4.0}); 

Aunque, no estoy seguro de por qué quiere pasar por la molestia. Esto no está permitido por ISO.

En general, se deben evitar accesos directos como este a favor de la legibilidad en todos los casos; la pereza no es un buen hábito para explorar (opinión personal, por supuesto)

+0

Acepto la legibilidad, y en la práctica, esta función en particular recibirá una dirección de memoria y será feliz. Sin embargo, durante las pruebas, a menudo solo quiero enchufar algunos valores aleatorios. Tu fragmento hace el truco, para bien o para mal :) ¡Gracias! – sinoth

+2

esto es válido en c99, pero nada más en cuanto a los estándares ... –

0

Por desgracia, sólo funciona con matrices de caracteres:

void func2(char arg[]) { 
} 

int main() 
{ 
    func2("hello"); 
    return 0; 
} 
17

Esto está marcado tanto en C y C++, por lo que vas a conseguir radicalmente diferentes respuestas

Si usted está esperando cuatro parámetros, se puede hacer esto:

void foo(float f[]) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    float f[] = {1, 2, 3, 4}; 
    foo(f); 
} 

Pero eso es bastante peligroso, ya que se podía hacer esto por accidente:

void foo(float f[]) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    float f[] = {1, 2}; // uh-oh 
    foo(f); 
} 

lo general, es mejor dejar ellos como parámetros individuales. Dado que usted no debe estar usando matrices primas de todos modos, usted puede hacer esto:

#include <cassert> 
#include <vector> 

void foo(std::vector<float> f) 
{ 
    assert(f.size() == 4); 

    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    float f[] = {1, 2, 3, 4}; 
    foo(std::vector<float>(f, f + 4)); // be explicit about size 

    // assert says you cannot do this: 
    foo(std::vector<float>(f, f + 2)); 
} 

una mejora, pero no demasiado grande.Se podría utilizar boost::array, pero en lugar de un error de tamaño coincidente, se inicializan a 0:

#include <boost/array.hpp> 

void foo(boost::array<float, 4> f) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    boost::array<float, 4> f = {1, 2, 3, 4}; 
    foo(f); 

    boost::array<float, 4> f2 = {1, 2}; // same as = {1, 2, 0, 0} 
    foo(f2); 
} 

Todo esto se fija en C++ 0x, cuando se añaden lista de inicialización de constructores:

#include <cassert> 
#include <vector> 

void foo(std::vector<float> f) 
{ 
    assert(f.size() == 4); 

    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    foo({1, 2, 3, 4}); // yay, construct vector from this 

    // assert says you cannot do this: 
    foo({1, 2}); 
} 

Y probablemente boost::array así:

#include <boost/array.hpp> 

void foo(boost::array<float, 4> f) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    foo({1, 2, 3, 4}); 

    foo({1, 2}); // same as = {1, 2, 0, 0} ..? I'm not sure, 
       // I don't know if they will do the check, if possible. 
} 
0

se puede escribir una clase constructor que permitiría sobre la misma sintaxis

// roughly 
template <typename C> 
class Builder { 
public: 
    template <typename T> 
    Builder(const T & _data) { C.push_back(_data); } 
    template <typename T> 
    Builder& operator()(const T & _data) { 
     C.push_back(_data); 
     return *this; 
    } 
    operator const C &() const { return data; } 
private: 
    C data; 

}; 

esta manera, puede utilizar la clase como

foo (const std :: vector & v);

foo (Constructor < std :: vector> (1) (2) (3) (4));

2

Puede técnicamente hacer referencia a una matriz, pero todavía no puede crear una lista de inicialización anónima, creo.

void func(int (&bla)[4]) 
{ 
    int count = sizeof(bla)/sizeof(bla[0]); 
    // count == 4 
} 

int bla[] = {1, 2, 3, 4}; 
func(bla); 

int bla1[] = {1, 2}; 
func(bla1); // <-- fails 

para C++ manera, mira boost::assign. Una manera bastante ordenada de llenar contenedores STL.

0

Para aumentar la diversión, puede usar plantillas para que sea de longitud variable.

template<std::size_t N> 
int chars(const char(&r)[N]){ 
    std::cout << N << ": " << r << std::endl; 
    return 0; 
} 

template<std::size_t N> 
int floats(const float(&r)[N]){ 
    std::cout << N << ":"; 
    for(size_t i = 0; i < N; i++) 
     std::cout << " " << r[i]; 
    std::cout << std::endl; 
    return 0; 
} 

int main(int argc, char ** argv) { 
    chars("test"); 
    floats({1.0f, 2.0f, 3.0f, 4.0f}); 
    return 0; 
} 
Cuestiones relacionadas