1

Say I am declaring a matrix like this--> long long int A[100][100]. Is there any way to assign the value 1 to all its elements at the time of declaring the matrix?

3 Answers3

1

You can use the fill_n method and initialize array like this:

std::fill_n(&A[0][0], sizeof(A) / sizeof(**A), 1);

Check this for more information about fill_na.

Hope it solves your question.

PRATHAMESH GIRI
  • 75
  • 1
  • 2
  • 11
1

Is there any way to assign the value 1 to all its elements at the time of declaring the matrix?

I interpret that as you want something constexpr and I'd use std::array instead of plain arrays since std::arrays are easier to work with.

I've made templates for make_array that creates a 1 dimensional array and templates for make_2d_array that creates a 2 dimensional array, using the first set of templates.

The goal of the templates is that if we for example want a 2d array with 2 rows and 3 columns of int with all ints initialized with 1, this should be created:

std::array<std::array<int, 3>, 2> A{{
    {1, 1, 1},
    {1, 1, 1}
}};

In the code below make_array<int, 3, 1>() will create the inner arrays, std::array<int, 3>{1, 1, 1}, and make_2d_array<int, 2, 3, 1>() will be equivalent to:

std::array<std::array<int, 3>, 2> A{
    make_array<int, 3, 1>(),         // std::array<int, 3>{1, 1, 1}
    make_array<int, 3, 1>()          // std::array<int, 3>{1, 1, 1}
};

These are a set of templates that can accomplish that:

#include <array>
#include <type_traits>
#include <utility>

//-------------------------------------------------------------
template <typename T, T init, std::size_t... X>
constexpr std::array<T, sizeof...(X)>
make_array(std::index_sequence<X...>) {
    //
    //        used for folding only then discarded below
    //                                          |
    return std::array<T, sizeof...(X)>{ ((void)(X), (init))... };
}

template <typename T, std::size_t X, T init = T{}>
constexpr std::array<T, X> make_array() {
    return make_array<T, init>(std::make_index_sequence<X>{});
}
//-------------------------------------------------------------
template <typename T, T init, std::size_t X, std::size_t... Y>
constexpr std::array< std::array<T, X>, sizeof...(Y)>
make_2d_array(std::index_sequence<Y...>) {
    return std::array< std::array<T, X>, sizeof...(Y)>{
        //
        //      Y used for folding only and discarded
        //      |
        ((void)(Y), make_array<T, X, init>())... 
    };
}

template <typename T, std::size_t Y, std::size_t X, T init = T{}>
constexpr std::array<std::array<T, X>, Y>
make_2d_array() {
    return make_2d_array<T, init, X>(std::make_index_sequence<Y>{});
}

It can then be used like this:

constexpr auto A = make_2d_array<int, 2, 3, 1>(); // Y=2, X=3, init value 1

Full demo (click on the Cppinsights link top left in the demo if you'd like to see how the folding unfolds)

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Since C++20 we could take advantage of `consteval` and `std::fill_n` beeing `constexpr`: https://godbolt.org/z/a6YGhs . Do you think that folding expressions and `index_sequence` have some advantages in terms of compilation time or generated code? – Bob__ Sep 25 '20 at 14:43
  • @Bob__ Oh, that's a nice C++20 addition! I expect folding and `index_sequence`s to make compilation a bit slower. If the same dimensions are used throughout the program I don't think it'll be noticeable - but if one uses a large number of different dimensions it may be noticeable. It's not recursive so the number of instances will still be reasonably low (4 per unique Y,X combination used). I usually care more about runtime and try to not rebuild parts not affected by recent changes. I hope the answer appeals to people with a similar mindset, as well as OP who asked for it (as I understood it) – Ted Lyngmo Sep 25 '20 at 14:55
  • Btw, I suggest you add your code as an answer. It's much simpler than mine and if OP can use C++20 - it'd be a done deal. – Ted Lyngmo Sep 25 '20 at 14:59
  • Well, that's a big [if](https://godbolt.org/z/zPnYEq). – Bob__ Sep 25 '20 at 15:08
  • @Bob__ I'll try it on my MSVC installation, brb.... Edit: Nope, not even there :-( ... still, it'd be a good answer (I'd vote for it) and it'll probably work in MSVC soon anyway. clang++ trunk compiles it fine btw. – Ted Lyngmo Sep 25 '20 at 15:18
1

As shown in Ted Lyngmo's answer, instead of a long long int A[100][100] we can declare and initialize a std::array<std::array<long long, 100>, 100> using a constexpr function.

Since C++20, it's possible to declare a function with a consteval specifier which

specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant.

Moreover, the algorithm std::fill_n has been made constexpr.

So that we can write the following two function templates:

#include <algorithm>
#include <array>

template <class Type, std::size_t Size>
consteval auto make_1d_array(Type value)
{
    std::array<Type, Size> result;
    std::fill_n(result.begin(), Size, value);
    return result;
}

template <class Type, std::size_t Rows, std::size_t Cols>
consteval auto make_2d_array(Type value)
{
    std::array<std::array<Type, Cols>, Rows> result;
    std::fill_n( result.begin(), Rows
               , make_1d_array<Type, Cols>(value) );
    return result;
}

Live demo.

Bob__
  • 12,361
  • 3
  • 28
  • 42