summaryrefslogtreecommitdiff
path: root/DEVELOPING.md
blob: d865a35d2dc7754b27fd677ccaa7bcbedf77a1aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# Modern C++ support

Mapbox GL Native supports the C++14 standard, and encourages contributions to
the source code using modern C++ idioms like return type deductions, generic
lambdas, `std::optional` and alike. However, we do not support all the features
from the final draft of the C++14 standard - we had to sacrifice support for
these features in order to support GCC from version 4.9 onwards.

The following C++14 features are **not supported** in Mapbox GL Native:

## [C++14 variable templates](https://isocpp.org/wiki/faq/cpp14-language#variable-templates)

Constructs like the example below are not supported:

```C++
template<typename T> constexpr T pi = T(3.14);
```

### Workarounds:

- If the variable is an alias, use the call the alias points to: [example](https://github.com/mapbox/mapbox-gl-native/commit/f1ac757bd28351fd57113a1e16f6c2e00ab193c1#diff-711ce10b54a522c948efc9030ffab4fcL269)
```C++
// auto foo = pi<double>;
auto foo = double(3.14);
```

- Replace variable templates with either functions or structs: [example 1](https://github.com/mapbox/mapbox-gl-native/commit/f1ac757bd28351fd57113a1e16f6c2e00ab193c1#diff-ffbe6cdfd30513aaa4749b4d959a5da6L58), [example 2](https://github.com/mapbox/mapbox-gl-native/commit/f1ac757bd28351fd57113a1e16f6c2e00ab193c1#diff-04af54dc8685cdc382ebe24466dc1d00L98)

## [C++14 aggregates with non-static data member initializers](http://en.cppreference.com/w/cpp/language/aggregate_initialization)

Constructs like the example below are not supported:

```C++
struct Foo {
    int x = { 0 };
};

// error: no matching function for call to 'Foo::Foo(<brace-enclosed initializer list>)'
int main() {
    Foo foo { 0 };
    return 0;
}
```

### Workarounds
- Replace data member initializers with default parameter values in default constructors:

```C++
struct Foo {
    Foo(int x_ = 0) : x(x_) {}
    int x;
};

int main() {
    Foo foo { 0 }; // works with default constructor
    return 0;
}
```

- Replace bracket initialization with regular round brackets or none:

```C++
struct Foo {
    Foo(int x_ = 0) : x(x_) {}
    int x;
};

int main() {
    Foo foo(); // works
    Foo bar; // also works
    return 0;
}
```

## [Extended `constexpr` support](https://isocpp.org/wiki/faq/cpp14-language#extended-constexpr)

GCC 4.9 strictly forbids `constexpr` usage in the following scenarios:
- No local variable declarations (not `static` or `thread_local`, and no uninitialized variables)
- Cannot mutate objects whose lifetime began with the constant expression evaluation
- Disable usage of if, switch, for, while, do-while (not goto) inside constexpr expressions
- Enforces that constexpr member functions are implicitly const

```C++
// sorry, unimplemented: use of the value of the object being constructed
// in a constant expression
struct Foo {
    int x, y;
    constexpr Foo(int i) : x(i), y(x) {}
};

// error: body of constexpr function 'constexpr int test1(int)' not a
// return-statement
constexpr int test1(int i) {
    int j = i;
    return j;
}

// error: body of constexpr function 'constexpr bool test2(int)' not a
// return-statement
constexpr bool test2(int i) {
    if (i > 0) {
        return true;
    } else {
        return false;
    }
}
```

### Workarounds

- Either remove `constexpr` specifier or replace it with `inline` in case of
  functions


## [Polymorphic lambdas](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68278)

GCC 5.2.0 crashes with polymorphic lambdas and this version of the compiler
is currently used in Qt Automotive. Luckily polymorphic lambdas are rarely
used/needed but we had one incident fixed by #9665.

### Workarounds

- Copy & Paste™ the code.


## [Inheriting Constructors](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm)

Compilers with only partial C++11 support causes compilation errors when using-declaration is used in derived class to inherit its base class's constructors `(e.g. using Base::Base;)`.

```C++
#include <vector>

template <typename T>
struct Varargs : std::vector<T>
{
    using std::vector<T>::vector;
};

// error: conflicts with version inherited from 'std::__1::vector<int, std::__1::allocator<int> >'
int main()
{
    Varargs<int> v;
    return 0;
}
```

### Workarounds

- Replace using-declaration (e.g. using Base::Base;) in derived class with `universal forwarding constructor`.

```C++
#include <vector>

template <typename T>
struct Varargs : std::vector<T>
{
    template <class... Args>
    Varargs(Args&&... args) : std::vector<T>(std::forward<Args>(args)...) {}
};

int main()
{
    Varargs<int> v;
    return 0;
}
```

Note: Using `universal forwarding constructor` may not be appropriate when derived class has additional members that are not in base class. Write constructors for the derived class explicitly instead of using `universal forwarding constructor` when the derived class has additional members.