Reputation: 5941
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?
Upvotes: 6
Views: 1394
Reputation: 78
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});
Upvotes: 2
Reputation: 21
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.
Upvotes: 0
Reputation: 1018
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 ...
Upvotes: 1
Reputation: 2073
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);
Upvotes: 10