Partial template argument deduction or workaround for std::array?
Asked Answered
D

4

6

C++17 allows us to have std::array's template arguments deduced. E.g., I can write

std::array ints = { 1, 2, 3 };

and ints will be of type std::array<int, 3>.

My question is: what if I wanted to specify only the type argument of the array but have the size of the array automatically determined?

The following does not work since it seems like all template arguments have to be specified:

std::array<size_t> sizes = { 1, 2, 3 };

My compiler complains and says: 'std::array': too few template arguments.

Is it possible to have the size of the array determined automatically by template argument deduction? If not, is it possible to create an array by only specifying its type but not its size?

Dejecta answered 10/1, 2019 at 9:26 Comment(1)
Possible duplicate of Trailing class template arguments not deducedHarelip
V
10

As far as I know, this cannot be done. But a helper method does the trick:

template<typename Type, typename ... T>
constexpr auto makeArray(T&&... t) -> std::array<Type, sizeof...(T)>
{
    return {{std::forward<T>(t)...}};
}

Usage example:

const auto container = makeArray<double>(-5.0, 0.0, 5.0, 10.0);
Viscosity answered 10/1, 2019 at 9:30 Comment(2)
See make_array() in the library fundamentals TS v2.Tinsmith
See std::to_aray too: en.cppreference.com/w/cpp/container/array/to_arrayFr
P
2

You can use std::to_array() directly:

std::array ints = { 1, 2, 3 };
auto int1 = std::to_array<int>({1, 2, 3});
auto int2 = std::to_array<double>({1, 2, 3});
Poisson answered 6/7, 2023 at 11:31 Comment(0)
F
1

If, I might be so bold as to expand on the Benjamin's answer. Conceptually one does not need always to be explicit about the result type.

template<
typename ... T,
typename CT = std::common_type_t< T... >
>
constexpr auto make_array(T&& ... t)
 -> std::array<  CT , sizeof...(T)>
{
    return { { static_cast<CT>( std::forward<T>(t) ) ...} };
}

Slightly simpler usage

constexpr auto std_arr = make_array(-5.0, 0.0, 5.0, 10.0);

The issue here might be, we are not exactly certain, what type of the std::array we will get. Provided we do care about it.

const auto std_arr = make_array(-5.0, 0, 5.0, 10.0, 42.13f );

Over "here", using MSVC, the latest, I get std array of doubles. If one's bed time reading is ISO C++ standard doc, the one might be sure what type will come out of std::common_type from the tool chain in use.

For the rest of us, literal suffixes will help

  constexpr auto sizes = make_array( 1UL, 2UL, 3UL );

But why stop with numbers? One can collect quickly, into an array, instances from the same hierarchy. Not caring about the result type.

    {
        const auto exceptions = make_array(
         std::exception{"SE"}, 
         std::runtime_error{"RE"}, 
         std::logic_error{"LE"} );
    }

A bit useless but somewhat weird and wonderful. One thing thou remember: this is compile time situation. Thus, I might prefer:

   constexpr auto sizes = std::array{ 1UL, 2UL, 3UL } ;

To answer the OP's question directly.

There is also C++20 std::to_array. For the exact result type and for a bit more comfortable usage:

  constexpr auto sizes = std::to_array<size_t>({ 0, 1, 3 });

Enjoy ...

Fr answered 14/9, 2019 at 9:56 Comment(2)
Take a look at en.cppreference.com/w/cpp/experimental/make_array and consider allowing the caller to override.Tinsmith
Ah, I was kind-of-a expecting someone to mention C++20 std::make_array ... my intention was not to produce implementation that might compete with that.Fr
C
0

There is a way, using nested templates. You can fully specify one while deducing the other:

template<typename E> struct typed
    {

    template<std::size_t N> struct array
        {
        E data[N];
        };

    template<std::size_t N> array(const E (&data)[N]) -> array<N>;

    };

typed<float>::array float3a = {{0.1f, 0.2f, 0.3f}};

auto float3b = typed<float>::array{{0.4f, 0.5f, 0.6f}};

using floatArray = typed<float>::array;

auto float3c = floatArray{{0.7f, 0.8f, 0.9f}};

This works with C++17. C++20 features may make this obsolete or allow more convenient syntax.

Crackup answered 5/7, 2023 at 16:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.