I've got the following function:
... getX()
{
static int x[] = {1, 2, 3};
return x;
}
I'd like to have it's return type as int(&)[3]
but don't wan't to specify the size (3) explicitly.
How do I do that?
(Please don't ask why do I want that.)
UPD
Well, OK, I need to pass a result to a template function taking int(&x)[N]
as a parameter (and I don't want to pass the size explicitly to that template function), so I don't see how a solution with returning a pair could work...
In C++14:
auto& getX()
{
static int x[] = {1, 2, 3};
return x;
}
Also, consider using std::array
instead of C-style arrays.
I cannot currently think of any Standard-compliant C++11 solution. Here's one using compound literals, assuming that your goal is to not repeat the elements and to deduce a reference-to-array:
#include <type_traits>
#define ITEMS 1, 2, 3
auto getX() -> decltype((int[]){ITEMS})
{
static int x[] = {ITEMS};
return x;
}
#undef ITEMS
int main()
{
static_assert(std::is_same<decltype(getX()), int(&)[3]>{});
}
Do you need the size available as a compile-time constant? I would suggest using gsl::span
(or roll your own). This is basically just a pointer and a size, that satisfies the range concept:
gsl::span<int> getX()
{
static int x[] = {1, 2, 3};
return x;
}
Another C++11 alternative (workaround), in case your theoretical scenario (not asking why ...) allows wrapping the static
array as a (literal) static data member of an otherwise stateless type:
class Foo
{
static constexpr int x[] = {1, 2, 3};
// delete ctor(s) ...
public:
static auto getX() -> std::add_lvalue_reference<decltype(x)>::type { return x; }
};
constexpr int Foo::x[];
Or, e.g.
class Foo
{
template <typename T, std::size_t n>
static constexpr std::size_t array_size(const T (&)[n]) { return n; }
static constexpr int x[] = {1, 2, 3};
// delete ctor(s) ...
public:
template<std::size_t N = array_size(x)>
static const int (&getX())[N] { return x; }
};
constexpr int Foo::x[];
Any of the two above applied in the use case you describe in your question:
template <std::size_t N>
void feedX(const int (&x)[N])
{
for (const auto num: x) { std::cout << num << "\n"; }
}
int main()
{
feedX(Foo::getX()); /* 1
2
3 */
}
This wouldn't help you in case your theoretical scenario would need to mutate the static data, though. You could tweak the above into a mutating-allowing scenario, but at the cost of having to specify the size of x
at its declaration, as it can no longer be (constant-)initialized and size-deduced at that point, and I believe this size explicitness is what you wanted to avoid in the first place. Anyway, for completeness:
class Foo
{
static int x[3];
public:
static auto getX() -> std::add_lvalue_reference<decltype(x)>::type { return x; }
};
int Foo::x[] = {1, 2, 3};
template <std::size_t N>
void feedAndMutateX(int (&x)[N])
{
for (auto& num: x) { std::cout << num++ << "\n"; }
}
int main()
{
feedAndMutateX(Foo::getX()); /* 1
2
3 */
feedAndMutateX(Foo::getX()); /* 2
3
4 */
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With