I know that in C++11, I can write
class foo {
static constexpr const char *one = "one";
}
However, when I try to do the same for an array
class bar {
static constexpr const float prim[4] = {2, 3, 5, 7};
}
(and reference it later on) I get an undefined reference linker error.
Is this just not possible for arrays or am I missing something in the syntax?
Static constexpr data member declarations aren't definitions in C++11/14, therefore you cannot odr-use prim.
To work around it, put the following statement somewhere in your cpp file as you would do with any other non-constexpr static data member:
constexpr const float bar::prim[4];
In other terms, this returns an undefined reference:
struct bar {
static constexpr const float prim[4] = {2, 3, 5, 7};
};
int main() {
auto *foo = bar::prim;
}
This doesn't:
struct bar {
static constexpr const float prim[4] = {2, 3, 5, 7};
};
constexpr const float bar::prim[4];
int main() {
auto *foo = bar::prim;
}
Because in the second case you are actually defining prim other than declaring it and thus you can get its address, use it by means of a reference, and so on...
Related
How to initialize static std:array that uses static const variable as size? I tried searching for similar questions but std::array is relatively new so theres not much to be found.
// ExampleClass.h
class ExampleClass {
public:
static const size_t NUMBER_OF_INDEXES = 5;
private:
static std::array<int, NUMBER_OF_INDEXES> myArray;
};
Like any other static data member, ExampleClass::myArray should have an out-of-line definition in exactly one translation unit, where you write down its type and its qualified name as usual:
std::array<int, ExampleClass::NUMBER_OF_INDEXES> ExampleClass::myArray = {1, 2, 3, 4, 5};
I've got the following function:
... getX()
{
static int x[] = {1, 2, 3};
return x;
}
I'd like to have its 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 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;
}
C++11
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 really want a reference, and have C++14, then decltype(auto) with a parenthesized id expression:
decltype(auto) get_arr() {
static int x[] = {1, 2 ,3};
return (x);
}
Will deduce as a reference to the array of that size. See it live, where the type of the reference is shown in the error message.
I would like to initalize a static const std::vector in class Foo to {0, 1, 2, 3, ..., n} where n is known at compile time based on the value of Last in the enum below. The goal is for Foo::all to contain all the values of the Fruit enum.
In foo.h:
enum Fruit { Apple, Orange, Banana, ..., Last };
class Foo {
public:
static const vector<int> all;
};
In foo.cpp:
// initialization of Foo::all goes here.
As a third option:
namespace {
std::vector<int> create();
}
const std::vector<int> Foo::all = create();
And create() can do anything it likes, even using push_back() for each element, because the vector it creates isn't const.
Or you could make create() a constexpr function using <index_tuple.h>
#include <redi/index_tuple.h>
namespace {
template<unsigned... I>
constexpr std::initializer_list<int>
create(redi::index_tuple<I...>)
{
return { I... };
}
}
const std::vector<int> Foo::all = create(typename redi::make_index_tuple<Last>::type());
You can use boost::irange:
auto range = boost::irange(0, n + 1);
const vector<int> Foo::numbers(range.begin(), range.end());
If your n is small enough and you use a compiler, which supports c++0x or c++11, just spell it out
const std::vector<int> Foo::all{0, 1, 2, 3, ..., n};
Fixed as per #Jonathan's explanation.
Pretty self-explanatory. The array is of an integral type, the contents are known and unchanging, and C++0x isn't allowed. It also needs to be declared as a pointer. I just can't seem to find a syntax that works.
The declaration in Class.hpp:
static const unsigned char* Msg;
Stuff in Class.cpp is really what I've tinkered with:
const unsigned char Class::Msg[2] = {0x00, 0x01}; // (type mismatch)
const unsigned char* Class::Msg = new unsigned char[]{0x00, 0x01}; // (no C++0x)
...etc. I've also tried initializing inside the constructor, which of course doesn't work because it's a constant. Is what I'm asking for impossible?
// in foo.h
class Foo {
static const unsigned char* Msg;
};
// in foo.cpp
static const unsigned char Foo_Msg_data[] = {0x00,0x01};
const unsigned char* Foo::Msg = Foo_Msg_data;
You are mixing pointers and arrays. If what you want is an array, then use an array:
struct test {
static int data[10]; // array, not pointer!
};
int test::data[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
If on the other hand you want a pointer, the simplest solution is to write a helper function in the translation unit that defines the member:
struct test {
static int *data;
};
// cpp
static int* generate_data() { // static here is "internal linkage"
int * p = new int[10];
for ( int i = 0; i < 10; ++i ) p[i] = 10*i;
return p;
}
int *test::data = generate_data();
I have a class and I want to have some bit masks with values 0,1,3,7,15,...
So essentially i want to declare an array of constant int's such as:
class A{
const int masks[] = {0,1,3,5,7,....}
}
but the compiler will always complain.
I tried:
static const int masks[] = {0,1...}
static const int masks[9]; // then initializing inside the constructor
Any idea on how this can be done?
Thanks!
class A {
static const int masks[];
};
const int A::masks[] = { 1, 2, 3, 4, ... };
You may want to fixate the array within the class definition already, but you don't have to. The array will have a complete type at the point of definition (which is to keep within the .cpp file, not in the header) where it can deduce the size from the initializer.
// in the .h file
class A {
static int const masks[];
};
// in the .cpp file
int const A::masks[] = {0,1,3,5,7};
enum Masks {A=0,B=1,c=3,d=5,e=7};
you can initialize variables only in the constructor or other methods.
'static' variables must be initialized out of the class definition.
You can do this:
class A {
static const int masks[];
};
const int A::masks[] = { 1, 2, 3, 4, .... };
Well, This is because you can't initialize a private member without calling a method.
I always use Member Initialization Lists to do so for const and static data members.
If you don't know what Member Initializer Lists are ,They are just what you want.
Look at this code:
class foo
{
int const b[2];
int a;
foo(): b{2,3}, a(5) //initializes Data Member
{
//Other Code
}
}
Also GCC has this cool extension:
const int a[] = { [0] = 1, [5] = 5 }; // initializes element 0 to 1, and element 5 to 5. Every other elements to 0.