Подтвердить что ты не робот

Как передать литерал константного массива функции, которая принимает указатель без использования переменной C/С++?

Если у меня есть прототип, который выглядит так:

function(float,float,float,float)

Я могу передать такие значения:

function(1,2,3,4);

Итак, если мой прототип:

function(float*);

Есть ли способ добиться чего-то подобного?

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

Просто ищет ленивый способ сделать это, не создавая временную переменную, но я не могу прикрыть синтаксис.

4b9b3361

Ответ 1

Вы можете сделать это на C99 (но не на ANSI C (C90) или любом текущем варианте С++) с составными литералами. См. Раздел 6.5.2.5 стандарта C99 для деталей gory. Вот пример:

// 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 также предоставляет это как расширение для C90. Если вы скомпилируете -std=gnu90 (по умолчанию), -std=c99 или -std=gnu99, он скомпилирует; если вы скомпилируете -std=c90, это не будет.

Ответ 2

Это отмечено как C, так и С++, поэтому вы получите радикально разные ответы.

Если вы ожидаете четыре параметра, вы можете сделать это:

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);
}

Но это довольно опасно, поскольку вы можете сделать это случайно:

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);
}

Обычно лучше оставить их в качестве отдельных параметров. Поскольку вы все равно не должны использовать необработанные массивы, вы можете сделать это:

#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));
}

Улучшение, но не много. Вы можете использовать boost::array, но вместо ошибки для несоответствующего размера они инициализируются на 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);
}

Все это будет исправлено в С++ 0x, когда добавляются конструкторы списка инициализаторов:

#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});
}

И, вероятно, boost::array:

#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.
}

Ответ 3

Вы можете создать составной литерал:

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

Хотя, я не уверен, почему вы хотите решить эту проблему. Это не разрешено ISO.

Как правило, таких ярлыков следует избегать в целях удобства чтения во всех случаях; лень не является хорошей привычкой исследовать (личное мнение, конечно)

Ответ 4

Плохая новость заключается в том, что для этого нет синтаксиса. Хорошей новостью является то, что это изменится со следующей официальной версией стандарта С++ (ожидается в следующем году или двух). Новый синтаксис будет выглядеть так, как вы описываете.

Ответ 5

Вы можете технически ссылаться на массив, но вы все равно не можете создать анонимный список инициализаторов, я думаю.

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

Для С++, посмотрите boost:: assign. Довольно аккуратный способ заполнения контейнеров STL.

Ответ 6

Нет, вы не можете этого сделать. У меня нет стандарта, доступного здесь, поэтому я не могу дать точную ссылку, но самое близкое к тому, что вы просите, это строковые константы, т.е.

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

обрабатывается компилятором как

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

Невозможно обработать другие типы переменных таким образом.

Ответ 7

К сожалению, он работает только с массивами символов:

void func2(char arg[]) {
}

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

Ответ 8

вы можете написать класс строителя, который позволит примерно такой же синтаксис

// 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;

};

таким образом, вы можете использовать класс как

foo (const std::vector и v);

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

Ответ 9

Чтобы добавить к забаве, вы можете использовать шаблоны, чтобы сделать ее переменной по длине.

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;
}