Можно ли построить массив фиксированного размера на месте в качестве аргумента функции? - PullRequest
0 голосов
/ 10 октября 2018

Это в основном вопрос о углу синтаксиса C ++, связанном с массивами фиксированного размера.

Предположим, у меня есть функция, которая использует информацию о типе, например:

template<class T> void fun(T const& t){
    std::cout << typeid(t).name() << std::endl;
}

Я могу передать значение или временный объект:

int i;
fun(i); // prints "int" ("i" actually)
fun(int{});   // prints "int" ("i" actually)

Однако я могуне могу сделать то же самое с массивами

double a[10][10];
fun(a); // ok, prints "a[10][10]" ("A10_A10_d" actually)

fun(double[10][10]); // doesn't compile
fun(double{}[10][10]); // doesn't compile
fun(double[10][10]{}); // doesn't compile
fun(double()[10][10]); // doesn't compile
fun(double[10][10]()); // doesn't compile
fun(double(&)[10][10]); // doesn't compile
fun(double(*)[10][10]); // doesn't compile

В принципе я мог бы сделать:

typedef double a1010[10][10];
fun(a1010{});

но, возможно ли обойтись без предопределения typedef?

Можно ли вообще создать массив фиксированного размера на месте в качестве аргумента функции?

Полный код:

template<class T> void fun(T const& t){
    std::cout << typeid(t).name() << std::endl;
}

typedef double a1010[10][10];

int main(){
    int i;
    fun(i); // prints "int" ("i" actually)
    double a[10][10];
    fun(a); // prints "a[10][10]" ("A10_A10_d" actually)
    fun(a1010{});

    fun(int{});   // prints "int"
/*  fun(double[10][10]); // doesn't compile
    fun(double{}[10][10]); // doesn't compile
    fun(double[10][10]{}); // doesn't compile
    fun(double()[10][10]); // doesn't compile
    fun(double[10][10]()); // doesn't compile
    fun(double(&)[10][10]); // doesn't compile
    fun(double(*)[10][10]); // doesn't compile
    */
    return 0;
}

Бонусные баллы (возможно, награда): А как насчет массивов переменного размера?

int N = 10;
f(double[N]);

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Вы пробовали много комбинаций с double, но, похоже, вы пропустили одну.

fun((double[10][10]){});

Это компилирует и дает: A10_A10_d

0 голосов
/ 10 октября 2018

Попробуйте:

fun((int[3]){1,2,3});
fun((int[5]){});

Что касается "бонусных баллов": массивы переменного размера не являются частью языка.Это расширение языка не работает с аргументами шаблона:

prog.cc: 4: 6: примечание: шаблон кандидата игнорируется: ошибка замещения: переменно измененный тип 'int [n]' не может использоватьсяв качестве аргумента шаблона fun (const T & t)

Edit

Как отметил Крис, в приведенном выше решении предлагается использовать составные литералы , которые являются расширением C ++,Существует решение, позволяющее избежать этого расширения в C ++ с использованием простого вспомогательного класса:

template <class T, std::size_t N>
struct my_array
{
    T data[N];
};

template <class T, std::size_t N>
void print(const T (&x)[N])
{
     for (auto i: x)
         std::cout << i << '\n';
}

int main()
{
    print(my_array<int,3>{9,10,11}.data);
}

Это работает хорошо, но требует добавления аргумента шаблона в my_array, который не выводится.С C ++ 17 возможно автоматически определить тип и размер:

template <class T, std::size_t N>
struct my_array
{
    constexpr my_array(std::initializer_list<T> x)
    {
       std::size_t i = 0;
       for (auto val : x)
           data[i++] = val;
    }
    T data[N];
};
template <class ...T>
my_array(T...) -> my_array<typename std::common_type<T...>::type, sizeof...(T)>;

int main()
{
    print(my_array{9,10,11}.data);
}

Для двумерных массивов это немного сложнее:

template <class T, std::size_t N1, std::size_t N2>
struct my_array2d
{
    constexpr my_array2d(std::initializer_list<std::initializer_list<T> > x)
    {
        std::size_t i = 0;
        for (const auto & row : x) {
            int j=0;
            for (const auto & val: row) {
                data[i][j++] = val;
            }
            i++;
        }
    }
    T data[N1][N2];
};
int main()
{
    work(my_array2d<int, 3, 2>{{9,1},{10,2},{11,3}}.data);
}

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

...